【1】歸並排序
歸並排序是建立在歸並操作上的一種有效的排序算法。該算法也是采用分治法(Divide and Conquer)的一個非常典型的應用。
歸並排序的算法復雜度為O(N*logN)。
歸並排序算法是穩定的(參見隨筆《常用排序算法穩定性分析》)。
【2】歸並排序邏輯分析與代碼實現
在分析歸並排序的邏輯之前,讓我們也利用一下分治法理念:先從基層做起(個人之拙見)。
先考慮一個簡單問題:如何將兩個有序數列進行合並?(注意:已有序數列)
好吧!其實,這個簡單的問題會給我們很大的啟迪。步驟整理如下:
<1>只要把兩個待合並數列的第一個數據進行比較,哪個小就先安置哪個,排序之后就在對應數列中跳過該數據索引(下標)。
<2>重復以上過程,直至有一個數列已經完全安置(即已為空)。
<3>再將另一個數列(未空數列)的所剩數據直接取出即可。
(1)示例代碼如下:
1 #include<iostream>
2 using namespace std; 3
4 //將有序數組ar[]和br[]合並到cr[]中
5 void MemeryArray(int a[], int n, int b[], int m, int c[]) 6 { 7 int i, j, k; 8
9 i = j = k = 0; 10 while (i < n && j < m) 11 { 12 if (a[i] < b[j]) 13 c[k++] = a[i++]; 14 else
15 c[k++] = b[j++]; 16 } 17
18 while (i < n) 19 c[k++] = a[i++]; 20
21 while (j < m) 22 c[k++] = b[j++]; 23 } 24
25 void PrintArr(int ar[],int n) 26 { 27 for(int i = 0; i < n; ++i) 28 cout<<ar[i]<<" "; 29 cout<<endl; 30 } 31
32 void main() 33 { 34 int ar[5] = {12, 23, 34, 45, 56}; 35 int br[5] = {13, 24, 35, 46, 60}; 36 int cr[10]; 37 cout<<"數組ar為:"<<endl; 38 PrintArr(ar, 5); 39 cout<<"數組br為:"<<endl; 40 PrintArr(ar, 5); 41 MemeryArray(ar, 5, br, 5, cr); 42 cout<<"合並后結果為:"<<endl; 43 PrintArr(cr, 10); 44 } 45
46 /*
47 數組ar為: 48 12 23 34 45 56 49 數組br為: 50 12 23 34 45 56 51 合並后結果為: 52 12 13 23 24 34 35 45 46 56 60 53 */
可以看出合並有序數列的效率是比較高的,完全可以達到O(n)。
那么,解決了上面的合並有序數列問題之后,我們再來看歸並排序。
歸並排序的基本思路就是先將待排序數組分成兩組A,B,然后如果這兩組組內的數據都是有序的,就可以利用上面的邏輯(合並有序數列邏輯)很方便的將這兩個有序數組數據再進行合並排序。
問題關鍵是如何讓這兩組組內數據有序呢?
可以將A,B組各自再分成二組。依次類推,當分出來的小組只有一個數據時,可以認為這個小組組內已經達到了有序,然后再合並相鄰的兩個小組就可以了。
這樣通過先遞歸的分解待排序數列,再合並數列就完成了歸並排序的過程。實現歸並排序。
仔細想,仔細想,仔細想,先想明白這幾句話,再看下面的代碼。
(2)歸並排序實現及測試示例代碼:
1 #include<iostream>
2 using namespace std; 3
4 #define MAXSIZE 10
5
6 //將兩個有序數列a[first...mid] 和 a[mid...last] 合並。
7 void mergearray(int a[], int first, int mid, int last, int temp[]) 8 { 9 int i = first, j = mid + 1; 10 int m = mid, n = last; 11 int k = 0; 12
13 while (i <= m && j <= n) 14 { 15 if (a[i] <= a[j]) 16 temp[k++] = a[i++]; 17 else
18 temp[k++] = a[j++]; 19 } 20
21 while (i <= m) 22 temp[k++] = a[i++]; 23
24 while (j <= n) 25 temp[k++] = a[j++]; 26
27 for (i = 0; i < k; ++i) 28 a[first + i] = temp[i]; 29 } 30 void mergesort(int a[], int first, int last, int temp[]) 31 { 32 if (first < last) 33 { 34 int mid = (first + last) / 2; 35 mergesort(a, first, mid, temp); //左邊有序
36 mergesort(a, mid + 1, last, temp); //右邊有序
37 mergearray(a, first, mid, last, temp); //再將兩個有序數列合並
38 } 39 } 40
41 bool MergeSort(int a[], int n) 42 { 43 int *p = new int[n]; 44 if (p == NULL) 45 return false; 46 mergesort(a, 0, n - 1, p); 47 delete[] p; 48 return true; 49 } 50
51 void PrintArr(int ar[],int n) 52 { 53 for(int i = 0; i < n; ++i) 54 cout<<ar[i]<<" "; 55 cout<<endl; 56 } 57
58 void main() 59 { 60 int ar[MAXSIZE] = {23, 34, 45, 78, 90, 12, 49, 92, 32, 19}; 61 PrintArr(ar, MAXSIZE); 62 bool bValue = MergeSort(ar, MAXSIZE); 63 if(!bValue) 64 { 65 cout<<"MergeSort Failed!! "<<endl; 66 } 67 PrintArr(ar, MAXSIZE); 68 }
以上內容參考文章:白話經典算法系列之五 歸並排序的實現
(3)另外一種代碼實現:
1 #include<iostream>
2 #include<malloc.h>
3 using namespace std; 4
5 #define MAXSIZE 10
6
7 void PrintArr(int ar[],int n) 8 { 9 for(int i = 0; i < n; ++i) 10 cout<<ar[i]<<" "; 11 cout<<endl; 12 } 13
14 static void merge(int ar[], int low, int mid, int high) 15 { 16 int i, k = 0; 17 //申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合並后的序列
18 int *temp = (int *)malloc((high - low + 1)*sizeof(int)); 19 int begin1 = low; 20 int end1 = mid; 21
22 int begin2 = mid + 1; 23 int end2 = high; 24
25 //比較兩個元素,選擇相對小的元素放入到合並空間,並移動指針到下一位置
26 for (k = 0; begin1 <= end1 && begin2 <= end2;) 27 { 28 if(ar[begin1] < ar[begin2]) 29 temp[k++] = ar[begin1++]; 30 else
31 temp[k++] = ar[begin2++]; 32 } 33
34 while(begin1 <= end1) //若第一個序列有剩余,直接拷貝出來粘到合並序列尾
35 temp[k++] = ar[begin1++]; 36 while(begin2 <= end2) //若第二個序列有剩余,直接拷貝出來粘到合並序列尾
37 temp[k++] = ar[begin2++]; 38
39 for (i = 0;i < k; i++) //將排序好的序列拷貝回數組中
40 { 41 ar[low+i] = temp[i]; 42 } 43
44 free(temp); 45 } 46 void merge_sort(int ar[],int begin,int end) 47 { 48 int mid = 0; 49 if(begin < end) 50 { 51 mid = (begin + end) / 2; 52 merge_sort(ar, begin, mid); 53 merge_sort(ar, mid + 1, end); 54 merge(ar, begin, mid, end); 55 } 56 } 57
58 void main() 59 { 60 int ar[] = {12, 14, 54, 5, 6, 3, 9, 8, 47, 89}; 61 merge_sort(ar, 0, MAXSIZE-1); 62 PrintArr(ar, MAXSIZE); 63 } 64
65 /*
66 *3 5 6 8 9 12 14 47 54 89 67 */
推薦掌握第一種。第二種僅僅助於理解歸並排序思想。當然,實現方式很多,那種好理解就使用那種,因人而異。
Good Good Study, Day Day Up.
順序 選擇 循環 堅持 總結