各种排序算法的实现和总结(部分原创)

直接上代码:

主程序:

#include <iostream>
using namespace std;

int main()
{
    int a[6];
    cout<<"请输入要排序的六个数字:";    //偷个懒,只输入6个数
    for(int k=0;k<6;k++)
    {
      cin>>a[k];
    }
    cout<<"排序前:";
     for(int m=0;m<6;m++)
        cout<<a[m]<<' ';
    cout<<endl;

//此处插入各种排序算法核心代码.......


    cout<<"排序后:";
    for(int m=0;m<6;m++)
    cout<<a[m]<<' ';

之后就是各种算法的代码了,在调用相应的算法函数前记得先在main函数中声明哦。

首先冒泡排序,这个比较简单,就像冒泡一样(可以从小到大,也可以从大到小),大的升上去,小的降下来。我这里用的是小的降下来,如下:

void popsort(int a[],int n)
{

    int j=0;
    for(int i=0;i<n-1;i++)
    {
        for(j=n-1;j>i;j--)
    {
        if(a[j]<a[j-1])
        {
      swap(a[j],a[j-1]]);
      }
    }
}

下面是选择排序,思路很简单,核心是从无序区(i+1~n-1)选择出最小的值与无序区的第一个数值交换。

 1 //选择排序:
 2 void selectsort(int a[],int length)
 3 {
 4     for(int i=0;i<length-1;i++)
 5     {
 6         int min_index=i;
 7         for(j=i+1;j<length;j++)
 8         {
 9             if(a[j]<a[min_index])
10             {
11                 min_index=j;
12             }
13         }
14         if(min_index!=i)
15         swap(a[min_index],a[i]);
16     }
17 }

下面是插入法,跟打扑克牌的思路是一样的,从无序区按顺序拿出一个与有序区进行比较放到合适的位置。

 1 void Insert_sort(int a[],int n)
 2 {
 3     for(int i=1;i<n;i++)
 4     {
 5         for(int j=i;j>0;j--)
 6         {
 7             if(a[j]<a[j-1])
 8             swap(a[j],a[j-1]);
 9 
10         }
11     }
12 
13 }

 

选择排序,冒泡法和插入法的共同点都是分为有序区和无序区,通过一定的方法将无序区的数据迁移到有序区,冒泡法和选择排序都是从无序区找出最大或最小放到有序区,而插入法则是直接从无序区随便选一个数据(从头开始)放到有序区,在放的过程中进行排序。简单说就是冒泡和选择是在无序区进行的排序操作,插入法是在有序区进行的排序操作。

 

然后是快速排序法,这个比较重要,采用的递归分治的思想,但是写起来稍微有点麻烦,得经常练练。我这里采用了csdn上的MoreWindows的白话经典上的写法,感觉这个比较清晰,理解起来不难。

void quick_sort(int a[],int l,int r)     
{
    if(l<r){
    int i=l,j=r;
    int x=a[l];           //初始化三个变量,其中l和r对应数组的两个边界(0和n-1),关键值x所在的位置相当于一个坑,需要别人来补,最初的坑的值已经保存到了x中。
    while(i<j)
    {
        while(j>i&&a[j]>x)//从右边开始找小于x的值
            j--;
        if(i<j)
            a[i++]=a[j];   //这里i++主要是因为下一步中a[i]不需要跟x比较,而是从a[i+1]开始比较。
        while(i<j&&a[i]<x)//从左边开始找第一个大于x的值
            i++;
        if(i<j)
            a[j--]=a[i];
    }
    a[i] = x;
    quick_sort(a, l, i - 1); // 对左边递归调用
    quick_sort(a, i + 1, r); //对右边递归调用

    }

我最早的思路是这样的,不是采用的赋值,而是用的交换,这样感觉好记忆一些,但是貌似效率不如直接赋值

void quick_sort(int a[],int l,int r)
{
    if(l<r){
    int i=l,j=r;
    int x=a[l];          
    while(i<j)
    {
        while(j>i&&a[j]>x)
            j--;
        if(i<j)
            swap(a[i++],a[j]);   //这里采用的swap函数代替的上面的方法1
        while(i<j&&a[i]<x)
            i++;
        if(i<j)
            swap(a[j--],a[i]);
    }
    quick_sort(a, l, i - 1); //此处为跟方法一的另一个不一样的地方,这里不需要另a[i]=x;了,因为之前交换以后a[i]已经是x了
    quick_sort(a, i + 1, r); 

    }
}

其实上面两个方法的对比正是快排的优化方法之一,另外几个优化方法包括

1,初始点的选择优化,即任意挑选m(比如3)个,选出最中间的数据作为初始点。

2,优化小数组排序时的排序方法,即因为快排适合于对大量数据进行排序,对小数量是体现不出优势,所以当数组数量(j-i)小于某个值(一般是7)时采用插入排序代替快排,这样能提高速度。

3,优化递归,即改成尾递归的形式,也就是把原来的两个递归调用改成一个,这样编译的速度会加快。

 

最后是归并排序:

归并排序写起来也比较复杂,主要分为两步,归和并,归是递归将原始数组分成小的数组,如下图示,最小的一层每个子数组有两个元素。

然后是并,并的过程并不难,难理解的是最后一步,每一步并完以后要把list1变成合并后的序列。

//归并排序
//首先给出合并函数
void Merge(int *list1,int list1_size,int *list2,int list2_size) { int i,j,k; i=j=k=0; int const maxsize=6; int temp[maxsize]; //按照大小将两个小序列(list1,list2)合并为大序列temp while(i<list1_size&&j<list2_size) { if(list1[i]<list2[j]) { temp[k++]=list1[i++]; } else { temp[k++]=list2[j++]; } } //下面是把list1或list2中还没有排到合并序列temp的数据放到temp里。 while(i<list1_size) { { temp[k++]=list1[i++]; } while(j<list2_size) { temp[k++]=list1[j++]; } } //最后把temp数组的数据传给list1,这样list1在递归往回退的时候就变成了list1和list2合并后的数组,而n在递归时每层已经确定,从而完成每一层的合并。该步骤很关键! for(int m=0;m<(list1_size+list2_size);m++) temp[m]=list1[m]; } void mergesort(int a[],int n) { //通过递归将原来的数组划分成很短的片段 int *list1=a; //这里最关键的就是a,list2可以由a和n所确定。 int list1_size=n/2; int *list2=a+n/2; int list2_size=n-list1_size; if(n>1) { mergesort(list1,list1_size); mergesort(list2,list2_size); Merge(list1,list1_size,list2,list2_size); }

常用的排序还有堆排序(基于完全二叉树的,思路比较简单,只需将顶的根节点元素拿出来放到最后面,然后重新更新堆,不断重复,,,有点像选择排序)

希尔排序(基于插入法,将数组进行分组,然后对分的组分别进行插入排序)。

有时间再写上面两个。

 

最后给出各个算法的时间复杂度

平均时间复杂度

插入排序  O(n2) 

冒泡排序 O(n2)  

选择排序 O(n2)  

快速排序O(n log n)  

堆排序 O(n log n)  

归并排序 O(n log n)  

希尔排序 O(n1.25)

 

 over~

posted @ 2016-04-19 17:18  Jymoon  阅读(678)  评论(0编辑  收藏  举报