歸併排序

  歸併排序(這裏主要介紹二路歸併)的基本思想是:將排序文件當作爲 n 個長度爲 1 的有序子文件,把此次子文件兩兩歸併(二路歸併),使獲得 [n/2] 個長度爲 2 的 有序子文件; 而後再把這[n/2] 個有序文件的子文件兩兩歸併,如此反覆,直到最後獲得一個長度爲 n的有序文件爲止, 這種排序方法稱爲二路歸併排序。html

  經過一個案例來講明其具體流程, 假設序列 爲 : 125 11 22 34 15 44 76 66 100 8 14 20 2 5 1   共 15 個元素算法

    初始狀態:  [125]  [11]  [22]  [34]  [15]  [44]  [76]  [66]  [100]  [8]  [14]  [20]  [2]  [5]  [1]     初始每一個元素看做是一個組,共 15 組數組

    一輪歸併:      [11 125]  [22 34]  [15 44]  [66 76]  [8 100]  [14 20]  [2 5]  [1]  兩兩歸併,落單的單獨做爲一組, 共 8 組數據結構

    二輪歸併:  [11 22 34 125]  [15 44 66 76]  [8 14 20 100] [1 2 5]  兩兩歸併,共 4 組ide

    三輪歸併:  [11 15 22 34 44 66 76 125]   [1 2 5 8 14 20 100]       兩兩歸併,共 2 組spa

    四輪歸併:  [1 2 5 8 11 14 15 20 22 34 44 66 76 100 125]  兩兩歸併,共 1 組,歸併完成code

 

  二路歸併排序中的核心操做時將數組中先後相鄰的兩個有序序列歸併爲一個有序序列。在實現過程當中須要引入另一個數組用於存放歸併好的結果。htm

 

  參考代碼:blog

  

 1 #include <stdio.h>
 2 
 3 #define MAX_NUM 80
 4 
 5 
 6 void Merge(int* a, int * b, int low, int m,int high)
 7 {
 8     int i = low;
 9     int j = m+1;
10     int k = low;
11     
12     while(i <= m && j <= high)
13     {
14         if(a[i] < a[j])        
15             b[k++]= a[i++];
16         else
17             b[k++] = a[j++];
18     }
19             
20     while(i <= m)
21         b[k++] = a[i++];
22             
23     while(j <= high)
24         b[k++] = a[j++];            
25     
26     for( i = low; i <= high;i++)
27     {
28         printf("%d ",b[i]);
29     } 
30     printf("  ");    
31     
32     
33 }
34 void MergePass(int* a, int* b, int len, int n)
35 {
36     int i;
37     for(i = 0; i+2*len-1 < n; i = i+ 2*len)    
38         Merge(a,b,i,i+len-1,i+2*len-1);
39 
40     if(i+len -1 < n)  // 若是還有兩個子文件,其中最後一個長度小於len 
41         Merge(a,b,i,i+len-1,n-1);
42     else
43     {
44         for(int j = i; j <n; j++)
45             b[j] = a[j];    
46     }
47     
48     printf("\n");    
49 }
50 
51 
52 void mergesort(int* a, int* b,int n)
53 {
54     int len = 1;
55     
56     while(len < n)
57     {
58         MergePass(a,b,len,n);
59         len =  len * 2;
60         MergePass(b,a,len,n);
61         len = len * 2;
62     }
63 }
64 
65 int main(int argc, char* argv[])
66 {
67     int a[MAX_NUM];
68     int b[MAX_NUM];
69     int n;    
70 
71     printf("Input total numbers: ");
72     scanf("%d",&n);
73 
74     if( n > MAX_NUM ) n = MAX_NUM;
75     
76     for(int i = 0; i < n;i++)
77     {
78         scanf("%d",&a[i]);
79         b[i] = a[i];
80     }
81 
82     printf("歸併步驟:\n");
83     mergesort(a,b,n);
84     
85     printf("歸併排序後的結果:\n");
86     for(int i = 0; i < n;i++)
87     {
88         printf("%d ",a[i]);
89     } 
90     printf("\n\n");    
91     
92     return 0;
93 } 
View Code

  案例運行結果:排序

    

 

   歸併排序算法的效率與穩定性分析

   二路歸併排序的過程須要進行[log n] 趟, 每一輪歸併排序的操做就是講兩個有序子文件驚醒歸併,而每一對有序子文件歸併時,記錄的比較次數均小於或等於記錄的移動次數,記錄移動次數均等於文件中記錄的個數,每一輪歸併的時間複雜度爲O(n)。所以,二路歸併排序的時間複雜度爲O(n log n)。

  

   二路歸併排序時穩定的,由於在每兩個有序子文件歸併是,若分別在兩個有序子文件中出現有相同關鍵字的記錄Merge 算法可以使前一個子文件中同一個關鍵字的記錄先複製,後一個文件中的同一關鍵字的記錄被後複製,從而確保了它們的相對次序不會改變。

 

  注:主要參考彭軍、向毅主編的 《數據結構與算法》

相關文章
相關標籤/搜索