排序算法:归并排序

来源:互联网 发布:淘宝买new3ds 编辑:程序博客网 时间:2024/06/16 21:52

归并排序

1. 将若干有序序列逐步归并为一个有序序列。2. 二路归并:最简单,将若干有序序列两两归并,直至形成一个有序序列。3. 采用的分治法。4. 二路归并非递归思路:    1. 将序列分成n个序列,每个序列一个元素,这样可以任务每个序列都是有序序列。    2. 逐一合并两个相邻的序列,使得每个序列长度为2.    3. 重复步骤2,直到序列的长度为n。    4. 子序列合并过程中有三种情况        1. 子序列数目为偶数且子序列长度相等。        2. 子序列数目为偶数且最后一个子序列长度小于其他子序列。        3. 子序列数目为奇数(最后剩下一个子序列)。5.比较占内存、效率高、稳定的排序算法。

复杂度

1. 一趟归并排序:O(n)。2. 整个归并排序,需要【log2n】取整趟,例如:8个数三趟。3. 所以总的视觉代价是O(nlogn),最好、最坏、平均的时间性能。4. 空间复杂度:非递归时候只需要O(n),小于递归时候占的内存,实际使用中推荐使用非递归方法。5. 排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。 

图示

代码实现

非递归方法

void Merge(int r[ ], int r1[ ], int s, int m, int t){/*    一次归并算法    s:start m:middle t:tail        r数组分为s——m,和m+1——t,两个部分。        r1为归并好的数组。*/    int i=s;    int j=m+1;    int  k=s;    while (i<=m && j<=t)    {           if (r[i]<=r[j])         {            r1[k++]=r[i++];   //取r[i]和r[j]中较小者放入r1[k]        }        else         {            r1[k++]=r[j++];         }    }    if (i<=m) while (i<=m)      //若第一个子序列没处理完,则进行收尾处理    {        r1[k]=r[i];         i++;        k++;    }       else  while (j<=t)       //若第二个子序列没处理完,则进行收尾处理    {        r1[k]=r[j];        k++;        j++;    }}void MergePass(int r[ ], int r1[ ], int n, int h){    //根据步长将相邻的两个子序列合并    int i=1;    //待归并记录至少有两个长度为h的子序列,之所以n+1,是因为我们从r[1]开始    while(i<=(n-2*h+1))    {        //若每个子序列相等且是偶数个,则一直走这个循环1 3 …… n-2*h+1 n+1(不成立跳出循环)        //将相邻的有序序列合并成一个有序序列        Merge(r, r1, i, i+h-1, i+2*h-1);        i = i + 2*h;    }    //待归并序列中有一个长度小于h,此时分为两段i——i+h-1,i+h——n,可推得i>(n-2*h+1)    if (i<n-h+1)     {   //当最后一个子序列长度小于其他子序列,且子序列数目为偶数        //n+1-2h<i<n+1-h        Merge(r, r1, i, i+h-1, n);     }    else     {        //待归并序列中只剩一个子序列,子序列数目为奇数,剩下的孤零零的一个子序列(长度<=h)        for (int k=i; k<=n; k++)            {            r1[k]=r[k];        }    } }void MergeSort1(int r[ ], int r1[ ], int n ){    cout<<"MergeSort:"<<endl;    int h=1;//初始序列长度为1,当序列长度达到n时候,意味着排序完成,此时h>=n    while (h<n)    {        int i ;        MergePass(r, r1, n, h);        cout<<"步长h:"<<h<<endl;        for (i = 1;i<10;i++)        {            cout<<r1[i]<<" ";        }        cout<<endl;        h=2*h;//每次序列合并之后,第一个单个序列长度为2h        int *p = r;        r = r1;        r1 = p;    }}

递归方法

void Merge(int r[ ], int r1[ ], int s, int m, int t){/*    一次归并算法    s:start m:middle t:tail        r数组分为s——m,和m+1——t,两个部分。        r1为归并好的数组。*/    int i=s;    int j=m+1;    int  k=s;    while (i<=m && j<=t)    {           if (r[i]<=r[j])         {            r1[k++]=r[i++];   //取r[i]和r[j]中较小者放入r1[k]        }        else         {            r1[k++]=r[j++];         }    }    if (i<=m) while (i<=m)      //若第一个子序列没处理完,则进行收尾处理    {        r1[k]=r[i];         i++;        k++;    }       else  while (j<=t)       //若第二个子序列没处理完,则进行收尾处理    {        r1[k]=r[j];        k++;        j++;    }}void MergeSort2(int r[ ], int r1[ ], int s, int t){     int m;    if (s==t)    {        r1[s]=r[s];     }    else     {        m=(s+t)/2;        MergeSort2(r, r1, s, m);    //归并排序前半个子序列        MergeSort2(r, r1, m+1, t);   //归并排序后半个子序列        Merge(r1, r, s, m, t);      //将两个已排序的子序列归并    }    }

注意:代码中的排序都是从r[1]开始的。

0 0
原创粉丝点击