#排序演算法#【5】合併排序

範長法@三月軟體發表於2014-07-21

  ok,塵埃落定。期待工作的氣息,越來越濃烈...繼續更新部落格,排序演算法的最後一個——合併排序

  合併排序(Merge Sort)是將兩個或多個有序表合併成一個有序表。也稱為二路合併。

  合併排序的基本思想是:對於兩個有續表合併初始時,把含有n個節點的待排序序列看做由n個長度為1的有序子表所組成麻將他們一次兩兩合併,得到長度為2的若干有序字表,再對這些字表進行兩兩合併,一直重複道長度為n,排序完成。

  資料示例如下:

  

 

  貼上程式碼:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #define ARRAYLEN 11
  4 //生成隨機數
  5 int CreateData(int a[],int n,int min,int max){
  6     int i,j,flag;
  7 
  8     srand(time(NULL));
  9 
 10     if((max-min+1) < n) return -1;
 11 
 12     for(i = 0 ; i < n ; i++){
 13         do{
 14             a[i] = rand()%(max-min+1)+min;
 15             flag = 0;
 16             for(j = 0 ; j < i ; j++){
 17                 if(a[i] == a[j]){
 18                     flag = 1;
 19                     break;
 20                 }
 21             }
 22         }while(flag);
 23     }
 24 }
 25 
 26 //對兩個陣列進行合併
 27 void MergeStep(int a[],int r[], int s,int m,int e){
 28     int i,j,k;
 29     k = s;    //s之前的序號都是已排過序的,從s進行下一次合併
 30     i = s;    //第一個陣列的開始序號
 31     j = m+1;  //第二個陣列的開始序號
 32     while(i<= m && j <= e){
 33         if(a[i] <= a[j])
 34             r[k++] = a[i++];
 35         else
 36             r[k++] = a[j++];
 37     }
 38 
 39     while(i <= m)
 40         r[k++] = a[i++];
 41     while(j <= e)
 42         r[k++] = a[j++];
 43     
 44 }
 45 
 46 //控制需要合併的兩個陣列的序號
 47 void MergePass(int a[],int r[],int n,int len){
 48     int s,e,i;    //合併兩個陣列,第一個的起始序號,和結束序號,第二個陣列對應的序號只需要+歩長值len即可
 49     s = 0;
 50     
 51     while(s+len < n){
 52         //保證至少有兩個序列進行排序
 53         e = s+2*len -1;
 54         if(e >= n){    //第二個陣列的結束序號
 55             e = n-1;
 56         }
 57 
 58         MergeStep(a,r,s,s+len-1,e);
 59 
 60         s = e+1;
 61     }
 62 
 63     //當不足兩個序列時退出排序,這時將可能剩餘的一個序列,直接放到r中
 64     if(s<n)
 65         for(;s<n;s++)
 66             r[s] = a[s];
 67 
 68 }
 69 
 70 
 71 //每次成倍增加歩長值進行合併
 72 void MergeSort(int a[],int n){
 73     int *p;    //分配一個和a一樣大小的輔助陣列空間
 74     int len = 1;    //歩長值
 75     int flag = 1;
 76     int i;
 77 
 78     if(!(p= (int *)malloc(sizeof(int)*n))){
 79         printf("記憶體分配失敗!\n");
 80         exit(0);
 81     }
 82 
 83     while(len < n){
 84         //再歩長值小於總長度的情況下,二路合併相鄰的陣列
 85         if(flag)    //交替兩個陣列,進行合併
 86             MergePass(a,p,n,len);
 87         else
 88             MergePass(p,a,n,len);
 89 
 90         len *= 2;    //歩長值每次增加一倍
 91         flag = 1-flag;
 92     }
 93 
 94     //當flag=1時,最終排序結果在p中,flag=0時,最終排序結果在a中
 95     //因此,當最後flag為1時,將最終結果在放到a中
 96     if(flag)
 97         for(flag = 0 ; flag < n ; flag++)
 98             a[flag] = p[flag];
 99     free(p);
100 }
101 
102 
103 int main(){
104     int i,a[ARRAYLEN];
105     /*for(i=0;i<ARRAYLEN;i++){
106         a[i] = 0;
107     }*/
108 
109     if(!CreateData(a,ARRAYLEN,1,100)){
110         printf("生成資料失敗!\n");
111         return -1;
112     }
113 
114     printf("原始資料:\n");
115     for(i = 0 ; i < ARRAYLEN ; i++){
116         printf("%d ",a[i]);
117     }
118     
119     MergeSort(a,ARRAYLEN);
120 
121     printf("\n排序後:\n");
122     for(i = 0 ; i < ARRAYLEN ; i++){
123         printf("%d ",a[i]);
124     }
125     printf("\n");
126 }

相關文章