COPY FROM:http://blog.csdn.net/left_la/article/details/8656953
歸併排序是利用"歸併"技術來進行排序。歸併是指將若干個已排序的子文件合併成一個有序的文件。常見的歸併排序有兩路歸併排序(Merge Sort),多相歸併排序(Polyphase Merge Sort),Strand排序(Strand Sort)。下面介紹第一種:
(一)兩路歸併排序
最差時間複雜度:O(nlogn)
平均時間複雜度:O(nlogn)
最差空間複雜度:O(n)
穩定性:穩定
兩路歸併排序(Merge Sort),也就是我們常說的歸併排序,也叫合併排序。它是建立在歸併操作上的一種有效的排序算法,歸併操作即將兩個已經排序的序列合併成一個序列的操作。該算法是採用分治法(Divide and Conquer)的一個非常典型的應用。
歸併操作的基本步驟如下:
1.申請兩個與已經排序序列相同大小的空間,並將兩個序列拷貝其中;
2.設定最初位置分別爲兩個已經拷貝排序序列的起始位置,比較兩個序列元素的大小,依次選擇相對小的元素放到原始序列;
3.重複2直到某一拷貝序列全部放入原始序列,將另一個序列剩下的所有元素直接複製到原始序列尾。
設歸併排序的當前區間是R[low..high],分治法的三個步驟是:
1.分解:將當前區間一分爲二,即求分裂點
2.求解:遞歸地對兩個子區間R[low..mid]和R[mid+1..high]進行歸併排序;
3.組合:將已排序的兩個子區間R[low..mid]和R[mid+1..high]歸併爲一個有序的區間R[low..high]。
遞歸的終結條件:子區間長度爲1(一個記錄自然有序)。
算法示意圖:
代碼實現:
- void Merge(int *a, int p, int q, int r)
- {
- int n1 = q-p+1;
- int n2 = r-q;
- int *L = new int[n1+1];
- int *R = new int[n2+1];
- int i, j, k;
- for (i=0; i<n1; i++){
- L[i] = a[p+i];
- }
- for (j=0; j<n2; j++){
- R[j] = a[q+j+1];
- }
- L[n1] = 10000000;
- R[n2] = 10000000;
- for (i=0, j=0, k=p; k<=r; k++)
- {
- if (L[i]<=R[j])
- {
- a[k] = L[i];
- i++;
- }else{
- a[k] = R[j];
- j++;
- }
- }
- delete []L;
- delete []R;
- }
- void MergeSort1(int *a, int p, int r)
- {
- if (p<r)
- {
- int q = (p+r)/2;
- MergeSort1(a, p, q);
- MergeSort1(a, q+1, r);
- Merge(a, p, q, r);
- }
- }
雖然插入排序的時間複雜度爲O(n^2),歸併排序的時間複雜度爲O(nlogn),但插入排序中的常數因子使得它在n較小時,運行得要更快一些。因此,在歸併排序算法中,當子問題足夠小時,採用插入排序算法就比較合適了。
代碼實現:
- void MergeSort2(int *a, int p, int r)
- {
- if ((r-p)>=50) // 小於50個數據的數組進行插入排序
- {
- int q = (p+r)/2;
- MergeSort2(a, p, q);
- MergeSort2(a, q+1, r);
- Merge(a, p, q, r);
- }else
- {
- InsertionSort(a+p, r-p+1);
- }
- }
MergeSort1與MergeSort2算法排序時間實驗結果比較:
數據量 |
1K |
10K |
100K |
1000K |
10000K |
MergeSort1 |
0.001s |
0.008s |
0.065s |
0.552s |
5.875s |
MergeSort2 |
<0.001s |
0.001s |
0.021s |
0.219s |
2.317s |