归并排序(含完整源码)

转载请注明出处:http://blog.csdn.net/ns_code/article/details/20306991

 

归并排序

首先考虑下如何将将二个有序数列合并。这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。

    实现思想      

    归并的含义很明显就是将两个或者两个以上的有序表组合成一个新的有序表。归并排序中一般所用到的是2-路归并排序,即将含有n个元素的序列看成是n个有序的子序列,每个子序列的长度为1,而后两两合并,得到n/2个长度为2或1的有序子序列,再进行两两合并。。。直到最后由两个有序的子序列合并成为一个长度为n的有序序列。2-路归并的核心操作是将一维数组中前后相邻的两个有序序列归并为一个有序序列。

    下面一系列图展示了2-路归并排序的过程:

    原始无序序列:


    第一次需要对各相邻元素进行两两归并,归并后结果如下:


    第三次需要对上图中相邻色块的元素进行两两归并,归并后的结果如下:


    接下来便是最后一次两两归并了,归并后便的到了有序的序列,如下:


   实现代码:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /******************************* 
  2.             归并排序 
  3. Author:兰亭风雨 Date:2014-02-28 
  4. Email:zyb_maodun@163.com 
  5. ********************************/  
  6. #include<stdio.h>  
  7. #include<stdlib.h>  
  8.   
  9. /* 
  10. 将有序的arr[start...mid]和有序的arr[mid+1...end]归并为有序的brr[0...end-start], 
  11. 而后再将brr[0...end-start]复制到arr[start...end],使arr[start...end]有序 
  12. */  
  13. void Merge(int *arr,int *brr,int start,int mid,int end)  
  14. {  
  15.     int i = start;  
  16.     int j = mid+1;  
  17.     int k = 0;  
  18.   
  19.     //比较两个有序序列中的元素,将较小的元素插入到brr中  
  20.     while(i<=mid && j<=end)  
  21.     {     
  22.         if(arr[i]<=arr[j])  
  23.             brr[k++] = arr[i++];  
  24.         else  
  25.             brr[k++] = arr[j++];  
  26.     }  
  27.   
  28.     //将arr序列中剩余的元素复制到brr中  
  29.     //这两个语句只可能执行其中一个  
  30.     while(i<=mid)  
  31.         brr[k++] = arr[i++];  
  32.     while(j<=end)  
  33.         brr[k++] = arr[j++];  
  34.   
  35.     //将brr中的元素复制到arr中,使arr[start...end]有序  
  36.     for(i=0;i<k;i++)  
  37.         arr[i+start] = brr[i];  
  38. }  
  39.   
  40. /* 
  41. 借助brr数组对arr[start...end]内的元素进行归并排序 
  42. 归并排序后的顺序为从小到大 
  43. */  
  44. void MSort(int *arr,int *brr,int start,int end)  
  45. {  
  46.     if(start < end)  
  47.     {  
  48.         int mid = (start+end)/2;  
  49.         MSort(arr,brr,start,mid);       //左边递归排序  
  50.         MSort(arr,brr,mid+1,end);       //右边递归排序  
  51.         Merge(arr,brr,start,mid,end);   //左右序列归并  
  52.     }  
  53. }  
  54. /* 
  55. 将该排序算法封装起来 
  56. */  
  57. void Merge_Sort(int *arr,int len)  
  58. {  
  59.     int *brr = (int *)malloc(len*sizeof(int));  
  60.     MSort(arr,brr,0,len-1);  
  61.     free(brr);  
  62.     brr = 0;  
  63. }  
  64.   
  65. int main()  
  66. {  
  67.     int num;  
  68.     printf("请输入排序的元素的个数:");  
  69.     scanf("%d",&num);  
  70.   
  71.     int i;  
  72.     int *arr = (int *)malloc(num*sizeof(int));  
  73.     printf("请依次输入这%d个元素(必须为整数):",num);  
  74.     for(i=0;i<num;i++)  
  75.         scanf("%d",arr+i);  
  76.   
  77.     printf("归并排序后的顺序:");  
  78.     Merge_Sort(arr,num);  
  79.     for(i=0;i<num;i++)  
  80.         printf("%d ",arr[i]);  
  81.     printf("\n");  
  82.   
  83.     free(arr);  
  84.     arr = 0;  
  85.     return 0;  
  86. }  

    小总结 

   归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。(参考:白话经典算法系列之五 归并排序的实现

归并排序的最好最坏和平均时间复杂度都是O(n*logn),但是需要额外的长度为n的辅助数组(每次递归调用前都会释放上次递归中传入到Merge函数的brr数组),因此空间复杂度为O(n),而不会因为栈的最大深度为O(logn)而积累至O(n*logn)占用额外空间是归并排序不足的地方,但是它是几个高效排序算法(快速排序、堆排序、希尔排序)中唯一稳定的排序方法。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值