二路歸並排序主要運用了“分治算法”,分治算法就是將一個大的問題划分為n個規模較小而結構相似的子問題。
這些子問題解決的方法都是類似的,解決掉這些小的問題之后,歸並子問題的結果,就得到了“大”問題的解。
二路歸並排序主旨是“分解”與“歸並”
分解:
1.將一個數組分成兩個數組,分別對兩個數組進行排序。
2.循環第一步,直到划分出來的“小數組”只包含一個元素,只有一個元素的數組默認為已經排好序。
歸並:
1.將兩個有序的數組合並到一個大的數組中。
2.從最小的只包含一個元素的數組開始兩兩合並。此時,合並好的數組也是有序的。
圖1. 歸並排序過程 圖2. 合並兩個有序數組
舉例說明:
1.圖中原始數組為{2,4,7,5,8,1,3,6},數組中元素的個數為8個。首先將8個元素的數組二分,每次分解后,
數組中元素的數目為原數組的一半。直到分解為只含有一個元素的數組。
2.將小的數組按序合並,每次合並后數組的大小為上層數組的一倍。此時數組中的元素都是按序排列的。
3.在合並兩個有序數組。如圖2
下面的是自頂向下遞歸實現2路歸並排序:
#include <iostream> using namespace std; void Merge(int * a, int low, int mid, int high) { int i = low, j = mid + 1, p = 0;//對應a數組的下標 int * r = new int[high - low + 1];//申請另一個對應大小的數組來存放排好序的數據 while (i <= mid && j <= high) { r[p++] = (a[i] <= a[j]) ? a[i++] : a[j++]; } while (i <= mid) r[p++] = a[i++]; while (j <= high) r[p++] = a[j++]; for (p = 0, i = low; i <= high; p++, i++) a[i] = r[p];//最后再把有序數據存進a數組中,使得a數組對應部分數據有序 delete[] r; } //自頂向下(遞歸實現) void MSort(int *a, int low, int high) { if (low<high) { int mid = (low + high) / 2; MSort(a, low, mid); MSort(a, mid + 1, high); Merge(a, low, mid, high); } } int _tmain(int argc, _TCHAR* argv[]) { int a[] = { 2,4,7,5,8,1,3,6 }; int n = sizeof(a) / sizeof(int); MSort(a, 0, n - 1); for (int i = 0; i<n; i++) cout << a[i] << " "; cout << endl; system("PAUSE"); return 0; }
參考資料:《算法導論》2.1章節