author: i.sshe
email: [email protected]
github: https://github.com/isshe
歸併排序[二路]
- 歸併排序是將要排序數組遞歸地分成兩半分別排序,然後將結果合併起來,完成排序.
- 歸併排序是最理想的直接排序算法(運行時間與NlogN成正比),執行過程具有穩定性.
歸併排序可以處理數百萬甚至更大規模的數組, 這是插入排序或選擇排序做不到的.
歸併排序示意圖:
1). 把前面部分元素和後面部分元素比較,小的放入結果數組.(注意此處的前半部分/後半部分已經排好序了)可以把後半部分倒序, 兩部分數組中最大的元素充當觀察哨, 這樣可以減少判斷.
代碼可以從
…
…
變爲
…
…- 合併代碼
void merge(int *a, int *b, int lo, int mid, int hi)
{
int i = lo;
int j = mid + 1;
int k = 0;
//copy a[lo..hi] to b[lo..hi].
for (k = lo; k <= hi; k++)
{
b[k] = a[k];
}
for (k = lo; k <= hi; k++)
{
if (i > mid) //到達邊緣
{
a[k] = b[j];
j++;
}
else if (j > hi) //到達邊緣
{
a[k] = b[i];
i++;
}
else if (b[i] > b[j])
{
a[k] = b[j];
j++;
}
else //b[i] < b[j]
{
a[k] = b[i];
i++;
}
}
}
自頂向下的歸併排序
- 軌跡圖
1). 排序E,M, 排序G,R,
2). 合併在一起.
3). 以此反覆. - 依賴樹
- 代碼
void top_down_merge_sort(int *a, int *b, int lo, int hi)
{
if(lo >= hi)
{
return ;
}
int mid = (lo + hi) / 2; //
top_down_merge_sort(a, b, lo, mid);
top_down_merge_sort(a, b, mid+1, hi);
merge(a, b, lo, mid, hi);
}
改進
- 對小規模子數組(長度小於15左右)使用插入排序, 可以縮短10%-15%的運行時間.
- 測試數組是否有序:添加一個判斷條件, 如果a[mid]<=a[mid+1],則認爲數組已經有序並跳過merge()方法.(<<算法 第四版>>p175頁,不懂)
- 不將元素複製到輔助數組: 要做到這一點需要調用兩種排序方法, 一種將數據從輸入數組排序到輔助數組, 一種將數據從輔助數組排序到輸入數組.(<<算法 第四版>>p175頁,不懂)
自底向上的歸併排序
歸併排序的另一種方法是: 兩兩歸併子數組.
1. 軌跡圖
注意:sz=1中, 奇數位置的總比偶數位置的短!
2. 歸併結果圖:
3. 代碼
void bottom_up_merge_sort(int *a, int *b, int len)
{
int sz = 0; //size:間隔:2, 4, 8...
int lo = 0;
int hi = 0;
int N = len;
for (sz = 1; sz < N; sz = sz + sz) //1+1=2, 2+2=4...控制間隔
{
for (lo = 0; lo < N - sz; lo += sz + sz) //控制次數
{
hi = (lo + sz + sz -1) < (N - 1) ? (lo + sz + sz -1) : (N -1);
merge(a, b, lo, lo+sz-1, hi);
}
}
}
3. 自底向上的歸併排序適合用於鏈表組織的數據.
歸併排序告訴我們:當能夠用其中一種方法解決一個問題的時候,你都應該試試另一種!
參考資料:
1. <<算法第四版>>
2. <<算法:C語言實現1-4部分>>