常見排序演算法之歸併排序
阿新 • • 發佈:2018-11-01
文章目錄
常見排序演算法之歸併排序
原地歸併方法
該方法將兩個不同的有序陣列歸併到第三個陣列中。
private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
// copy to aux[]
for (int k = lo; k <= hi; k++) {
aux[k] = a[k];
}
// merge back to a[]
int i = lo, j = mid+1;
for (int k = lo; k <= hi; k++) {
if (i > mid) a[k] = aux[j++];
else if (j > hi) a[k] = aux[i++];
else if (less(aux[j], aux[i])) a[k] = aux[j++];
else a[k] = aux[i++];
}
}
自頂向下的歸併排序
自頂向下的歸併排序應用了分治的思想,要對子陣列a[lo…hi]進行排序,先將它分為a[lo…mid]和a[mid+1…hi]兩部分,分別通過遞迴呼叫將它們單獨排序,最後將有序的子陣列歸併為最終的排序結果。
圖為自頂向下的歸併排序中歸併結果的軌跡
public class Merge {
public static void sort(Comparable[] a) {
Comparable[] aux = new Comparable[a.length];
sort(a, aux, 0, a.length-1);
}
private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi) {
if (hi <= lo) return;
int mid = lo + (hi - lo) / 2;
sort(a, aux, lo, mid);
sort(a, aux, mid + 1, hi);
merge(a, aux, lo, mid, hi);
}
}
自底向上的歸併排序
實現歸併排序的另一種方法是先歸併那些微型陣列,然後再成對歸併得到子陣列,如此這般地多次遍歷整個陣列,直到我們將整個陣列歸併到一起。
圖為自底向上的歸併排序中歸併結果的軌跡
public class MergeBU {
public static void sort(Comparable[] a) {
int n = a.length;
Comparable[] aux = new Comparable[n];
for (int len = 1; len < n; len *= 2) {
for (int lo = 0; lo < n-len; lo += len+len) {
int mid = lo+len-1;
int hi = Math.min(lo+len+len-1, n-1);
merge(a, aux, lo, mid, hi);
}
}
}
}
特點
- 歸併排序的空間複雜度不是最優的
- 和選擇排序一樣,排序的效能不受輸入資料的影響,但表現比選擇排序好的多
複雜度分析
- 最壞情況時間複雜度 O(nlogn)
- 最好情況時間複雜度 O(nlogn)
- 平均情況時間複雜度 O(nlogn)
- 空間複雜度 O(n)
- 穩定
參考資料
- Wikipedia
- Algorithms (Fourth Edition)
- 十大經典排序演算法