(1.3.5)归并排序:二路归并

来源:互联网 发布:stc12c系列单片机 编辑:程序博客网 时间:2024/05/29 19:30

归并排序(Merge Sort)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列。

归并排序的具体做法:

  1. 把原序列不断地递等分,直至每等份只有一个元素,此时每等份都是有序的。
  2. 相邻等份合,不断合并,直至合并完全。

二路归并

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序最常用的是二路归并,即把两个小的有序的序列和并成一个大的有序序列:合二为一。

一个二路归并的流程图是这样的:

多路归并无非是多个有序的小序列合并成一个大的有序序列,道理和二路归并一样。

先来看下如何把两个有序的序列合并成一个大的有序序列,代码如下:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  *把有序序列a和b,合并成c  
  3.  *该算法成立前提: a和b已经有序   
  4.  */   
  5. void merge(int a[], int na, int b[], int nb, int c[])  
  6. {  
  7.     if(a && b && c && na >0 && nb >0)  
  8.     {  
  9.         int i,j,k;  
  10.         i = j = k = 0;  
  11.         //不断地比较a和b的头部元素,较小的存入c   
  12.         while(i < na && j < nb)  
  13.         {  
  14.             if(a[i] <= b[j]) // <= 保持算法的稳定性  
  15.                 c[k++] = a[i++];  
  16.             else  
  17.                 c[k++] = b[j++];  
  18.             /*另一种更有效的做法是这样的  
  19.             while(i < na && a[i] <= b[j]) 
  20.                 c[k++] = a[i++]; 
  21.             while(j < nb && b[j] < a[i]) 
  22.                 c[k++] = b[j++]; 
  23.             */  
  24.         }  
  25.         //把a或b中剩余的元素直接存入c   
  26.         /*  也可以这样: 
  27.          *  memcpy(c+k, a+i, (na-i)sizeof(int)); 
  28.          * 下同 
  29.          */  
  30.         while(i < na)  
  31.             c[k++] = a[i++];  
  32.         while(j < nb)  
  33.             c[k++] = b[j++];  
  34.     }  
  35. }  

可以看出,二路归并的时间复杂度是O(n),n是原序列的数据规模。以上代码是归并排序的基础,弄懂了它,就很好写归并排序了,看下归并排序的流程图:


可以看出,上半部分不断地递归深入:不断地均分原序列,直到每一部分只含有一个元素。下半部分,开始递归返回,通过反复调用二路归并算法,把相邻的有序子序列合并成一个规模更大的序列。

理解了这些,相信就很容易写出归并排序的代码了:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //把[first, mid]和[mid+1, last]范围内的数据合并    
  2. void mergeArray(int a[], int b[], int first, int mid, int last)  
  3. {  
  4.     int i, j, k;  
  5.     i = first, j = mid + 1, k = 0;  
  6.     while (i <= mid && j <= last)  
  7.     {  
  8.         while(i <= mid && a[i] <= a[j])  
  9.             b[k++] = a[i++];  
  10.         while(j <= last && a[j] < a[i])  
  11.             b[k++] = a[j++];      
  12.     }  
  13.     /*  也可以这样: 
  14.      *  memcpy(b+k, a+i, (mid-i+1)sizeof(int)); 
  15.      * 下同 
  16.      */  
  17.     while (i <= mid)  
  18.         b[k++] = a[i++];  
  19.     while (j <= last)  
  20.         b[k++] = a[j++];  
  21.     //[first,last]范围内的数据已有序,则写回原数组  
  22.     for (i = 0; i < k; i++)  
  23.         a[first + i] = b[i];  
  24. }  
  25. void mergesort(int a[], int b[], int first, int last)  
  26. {  
  27.     if (first < last)  
  28.     {  
  29.         int mid = first + ((last - first) >> 1);  
  30.         mergesort(a, b, first, mid);  
  31.         mergesort(a, b, mid + 1, last);  
  32.         mergeArray(a, b, first, mid, last);  
  33.     }  
  34. }  
  35. void MergeSort(int a[], int n)  
  36. {  
  37.     if (a && n > 1)  
  38.     {  
  39.         int *b = new int[n];  //构建辅助数组  
  40.         mergesort(a, b, 0, n - 1);  
  41.         delete[]b;  
  42.     }  
  43. }  


在排序过程中,我们使用了一个相同大小的临时辅助数组。

算法分析:

1.算法的复杂度

对数组长度为n的序列进行归并排序,则大约要进行logn次归并,每一次合并都是线性时间O(n)。故粗略的计算出归并排序的时间复杂度是O(nlogn)(最好、最差都是这样)。空间复杂度是O(n)。详细的时间复杂度分析是这样的:

对长度为n的序列归并排序,需要递归的对长度为n/2的子序列进行归并排序,最后把两段子序列二路归并。递推关系是这样的:T(n)=2T(n/2)+O(n),显然T(1)=O(1),解得T(n)=o(nlogn)。

2.稳定性

归并排序是稳定的,并且是时间复杂度为o(nlogn)的几种排序(快速排序、堆排序)中唯一稳定的排序算法。

3.存储结构

顺序存储和链式存储都行。

另外,归并排序多用于外排序中。


转载请注明出处,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/34463409


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小腿走多了酸痛怎么办 腿肚受凉了酸痛怎么办 晚上腿疼的睡不着觉怎么办 走路走多了腿酸怎么办 跳完蛙跳大腿疼怎么办 走路走多了脚疼怎么办 走太多路脚酸痛怎么办 走路走的腿酸痛怎么办 路走得太多腿疼怎么办 走路走的足弓疼怎么办 走路走多了膝盖怎么办 2岁宝宝走路一只脚内八字怎么办 6岁宝宝o型腿怎么办 一岁宝宝o型腿怎么办 宝宝一岁o型腿怎么办 宝宝一周两个月走路弓着腿怎么办 宝宝腿走路膝盖弯曲怎么办 两岁宝宝不爱走路怎么办 水鸭子脚不能走了怎么办 鸭子坐着脚走不动怎么办 鸭子步走了腿疼怎么办? 跳爵士舞没感觉怎么办 军校学员体能考核不达标怎么办 俯卧撑新兵连做不动怎么办 宝宝胆小不敢上体能课怎么办 28岁老太太抬头纹剩两颗怎么办 大腿前侧抽筋痛怎么办 电脑看片缓冲慢怎么办 跑步跑的腿疼怎么办 第一次去健身房练瑜伽不会怎么办 跑步过后腿筋疼怎么办 俯卧撑只能做20个怎么办 被裤裆峰咬了怎么办? 新兵5公里不想跑怎么办 老公掉粪坑了你怎么办 在部队被欺负了怎么办 衣服上的标志洗掉了怎么办 整件白衬衣被染怎么办 遇到敲诈小混混该怎么办 纯棉衣服洗长了怎么办 纯棉的衣服洗后长了怎么办