归并排序

归并排序,不单单是归并排序,应该更重要的是一种分治的思想。把问题大而化小,再将小问题的结果汇总,得到大问题的解。

递归的写法更能体现归并的分治思想,但是递归调用,当层次非常多的时候,会影响性能,现在考虑如何把归并的递归方式变成非递归方式。

归并的完整描述是:

假设初始序列含有n个记录,则可看成是n个有序的子序列,每个子序列的长度为1, 然后两两归并,得到[n/2]个升序为2(或1,最后一个可能为1)的子序列,再将此序列两两归并,得到 [n/4]个长度为4(或者<4)的子序列, .....直到整个序列有序为止,此为2-路归并排序。

按照此方法,写非递归方法时,就不难了。即我们按照子序列的步长,从1 到 n, 为n时,序列已有序,进行两两归并即可。

如:目录待排序的序列为: (2)  (27)     (454)      (23)      (76)     (13)     (30)

1趟子序列长序为1                 ----------      ----------------       ---------------     ----

第一趟两两归并,结果为: (2    27)          (23   454)       (13     76)    (30)

2趟子序列长序为2                 -------------------------------        --------------------

第二趟两两归并,结果为:(2     23      27   454)     (13     30       76)

3趟子序列长度为4                ---------------------------------------------------

第三趟两两归并,结果为 :(2     13      23     27     30       76      454) 

简单的参考代码如下:

[html]  view plain copy
  1. /**  
  2.  * 非递归的归并排序  
  3.  */  
  4.   
  5. #include <stdio.h>  
  6.   
  7. //sr[i,m]  和 sr[m+1, n]都有序,现在把它们合并成整体有序存放到tr[i, n]中  
  8. void merge(int sr[], int tr[], int i, int m, int n)  
  9. {  
  10.     int j, k, t_pos;  
  11.     for (j=m+1, k=i; i<=m&&j<=n; k++){   
  12.         if (sr[i]<=sr[j]){  
  13.             tr[k] = sr[i];  
  14.             i++;  
  15.         } else {  
  16.             tr[k] = sr[j];  
  17.             j++;  
  18.         }  
  19.     }     
  20.       
  21.     // copy the rest elements  
  22.     if (i<=m){  
  23.         // tr[k..n] = sr[i..m]  
  24.         for (; i<=m; i++, k++)  
  25.             tr[k] = sr[i];  
  26.     } else if (j<=n){  
  27.         // tr[k..n] = sr[j..n]  
  28.         for (; j<=n; j++, k++)  
  29.             tr[k] = sr[j];  
  30.     }  
  31. }  
  32.   
  33. //将长度为s的子序列进行两两合并  
  34. void merge_len(int src[], int dst[], int s, int len)  
  35. {  
  36.     int i = 0;  
  37.     while (i <= len-2*s){ //保证剩余的长度>=2s ; len-i >2s  ==>  i<=len-2s  
  38.         merge(src, dst, i, i+s-1, i+2*s-1);  
  39.   
  40.         i = i+2*s;  
  41.     }  
  42.   
  43.     if (len-i>s){//剩余两段有序部分  
  44.         merge(src, dst, i, i+s-1, len-1);  
  45.     } else { //只剩余一段,直接复制到目标数组中  
  46.         for (; i<len; i++)  
  47.             dst[i] = src[i];  
  48.     }  
  49. }  
  50.   
  51. #define N 100  
  52. void merge_sort(int arr[], int len)  
  53. {  
  54.     int s = 1, i;  
  55.     int tmp[N] = {0};  
  56.     while (s<len){  
  57.         merge_len(arr, tmp, s, len);      
  58.         s += s;//步长增大  
  59.   
  60.         merge_len(tmp, arr, s, len);      
  61.         s += s;  
  62.     }  
  63. }  
  64.   
  65. int main()  
  66. {  
  67.     int arr[N] = {0};  
  68.   
  69.     int n, i;  
  70.     printf("Please input arr size: ");  
  71.     scanf("%d", &n);  
  72.   
  73.     printf("Please input arr elements: ");  
  74.     for (i=0; i<n; i++)  
  75.         scanf("%d", &arr[i]);  
  76.   
  77.     merge_sort(arr, n);  
  78.   
  79.     printf("Sort results: \n");  
  80.     for (i=0; i<n; i++)  
  81.         printf("%d\t", arr[i]);  
  82.     printf("\n");  
  83.   
  84.     return 0;  
  85. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值