演算法學習筆記--歸併排序
阿新 • • 發佈:2019-01-03
歸併排序:一種簡單的利用遞迴排序的演算法,將一個數組先(遞迴地)將它分成兩半分別排序,然後將兩半分別排序,然後將結果歸併起來。
原地歸併的抽象方法:
public static void merge(int[] a, int lo, int mid, int hi){
//將a[lo..mid] 和 a[mid+1..hi] 歸併
int N = a.length;
int[] b = new int[N];
int i = lo;
int j = mid + 1;
for (int k = lo; k <= hi; k++) {
b[k] = a[k];
}
//歸併回a[lo..hi]
for (int k = lo; k <= hi; k++) {
if(i > mid){
a[k] = b[j++];
}else if(j > hi){
a[k] = b[i++];
} else if(b[i] < b[j]){
a[k] = b[i++];
}else{
a[k] = b[j++];
}
}
}
先將所有元素複製到吧b[]中,然後再歸併回a[]中。
歸併軌跡如下圖:
自頂向下的歸併排序:
這是基於原地歸併的抽象實現的遞迴歸併,應用了高效演算法設計中的分治思想的典型的例子。
public static void sort(int[] a, int lo, int hi){ // lo,hi 陣列下標
if(hi <= lo){
return;
}
int mid = lo + (hi-lo)/2;
sort(a, lo, mid); //將左半邊排序
sort(a, mid+1 , hi); //將右半邊排序
Merge.merge(a, lo, mid, hi); //原地歸併的抽象方法
}
要對陣列 a[lo..hi] 進行排序,先將它分為a[lo..mid] 和 a[mid+1..hi] 兩部分,分別通過遞迴呼叫將它們單獨排序,最後將有序的子陣列歸併為最終的排序結果。
歸併結果軌跡:
自底向上的歸併排序:
這種排序的思想是:先歸併那些微型陣列,然後再成對歸併得到的子陣列。
先進行兩兩歸併,然後再四四歸併,再八八歸併。。。
public static void sort(int[] a){
int N = a.length;
for (int sz = 1; sz < N; sz = 2*sz) { //子陣列的大小
for (int lo = 0; lo < N - sz; lo += 2*sz) { // lo為子陣列的索引
Merge.merge(a, lo, lo + sz - 1, Math.min(N - 1, lo + 2*sz -1));
}
}
}
歸併軌跡圖:
特點:
對於長度為N的任意陣列,歸併排序需要(1/2)N/lgN至NlgN次比較,最多需要訪問陣列6NlgN次。
可以用歸併排序處理數百萬甚至更大規模的陣列。