歸併排序是典型的分治法:
時間複雜度:O(N log N)(最好/最壞/平均),空間複雜度 O(N)(輔助陣列),穩定排序。
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) {
int[] a = {6, -2, 7, 8, 3, 4, 12, 1, 0, -3, -8, 3, 4, 7};
System.out.println("排序前:" + Arrays.toString(a));
sort(a, 0, a.length - 1);
System.out.println("排序後:" + Arrays.toString(a));
}
public static void sort(int[] a, int low, int high) {
if (low < high) {
int mid = (low + high) >>> 1; // 防溢出
sort(a, low, mid);
sort(a, mid + 1, high);
merge(a, low, mid, high);
}
}
private static void merge(int[] a, int low, int mid, int high) {
int[] temp = new int[high - low + 1];
int i = low, j = mid + 1, k = 0;
// 合併兩有序區間
while (i <= mid && j <= high) {
temp[k++] = (a[i] <= a[j]) ? a[i++] : a[j++]; // <= 保證穩定性
}
while (i <= mid) temp[k++] = a[i++];
while (j <= high) temp[k++] = a[j++];
// 複製回原陣列
System.arraycopy(temp, 0, a, low, temp.length);
}
}
public static void sortIterative(int[] a) {
int n = a.length;
int[] temp = new int[n];
for (int width = 1; width < n; width <<= 1) { // 子陣列寬度 1,2,4,8...
for (int i = 0; i < n; i += 2 * width) {
int low = i;
int mid = Math.min(i + width - 1, n - 1);
int high = Math.min(i + 2 * width - 1, n - 1);
merge(a, temp, low, mid, high);
}
// 交換 a 與 temp 角色,避免重複複製
int[] swap = a; a = temp; temp = swap;
}
// 若最終結果在 temp,複製回 a
if (a != temp) System.arraycopy(a, 0, temp, 0, n);
}
private static void merge(int[] src, int[] dest, int low, int mid, int high) {
int i = low, j = mid + 1, k = low;
while (i <= mid && j <= high) dest[k++] = (src[i] <= src[j]) ? src[i++] : src[j++];
while (i <= mid) dest[k++] = src[i++];
while (j <= high) dest[k++] = src[j++];
}
a[mid] <= a[mid+1],直接返回,跳過合併。src/dest 引用,省去 System.arraycopy 開銷。ForkJoinPool 併行處理左右半部,Java 8+ Arrays.parallelSort 內部即採用平行歸併。| 維度 | 歸併排序 | 快速排序 |
|---|---|---|
| 時間複雜度 | O(N log N) 穩定 | 平均 O(N log N),最壞 O(N²) |
| 空間複雜度 | O(N) 輔助陣列 | O(log N) 棧(原地分區) |
| 穩定性 | 穩定 | 不穩定 |
| 緩存友好 | 順序訪問,佳 | 隨機訪問,較差 |
| 適用場景 | 外部排序、連結串列、需穩定性 | 記憶體內通用排序、原地排序 |