歸併排序是典型的分治法:
時間複雜度:O(n log n)(最好/最壞/平均)。空間複雜度:O(n)(輔助數組)。穩定排序。
以數組 {3, 2, 4, 1} 為例:
分解階段:
{3, 2, 4, 1}
/ \
{3, 2} {4, 1}
/ \ / \
{3} {2} {4} {1}
歸併階段:
{3} {2} -> {2, 3}
{4} {1} -> {1, 4}
{2, 3} {1, 4} -> {1, 2, 3, 4}
public class MergeSort {
/** 入口方法 */
public static void sort(int[] array) {
if (array == null || array.length < 2) return;
mergeSort(array, 0, array.length - 1);
}
/** 遞歸分解 */
private static void mergeSort(int[] arr, int left, int right) {
if (left < right) {
int mid = left + ((right - left) >> 1); // 防止溢出
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
/** 合併兩個有序區間 [left, mid] 和 [mid+1, right] */
private static void merge(int[] arr, int left, int mid, int right) {
int[] temp = new int[right - left + 1];
int i = left, j = mid + 1, k = 0;
// 雙指針比較合併
while (i <= mid && j <= right) {
temp[k++] = (arr[i] <= arr[j]) ? arr[i++] : arr[j++]; // <= 保證穩定性
}
// 複製剩餘元素
while (i <= mid) temp[k++] = arr[i++];
while (j <= right) temp[k++] = arr[j++];
// 寫回原數組
System.arraycopy(temp, 0, arr, left, temp.length);
}
// 測試
public static void main(String[] args) {
int[] arr = {3, 2, 4, 1, 5, 0, -1, 8};
System.out.println("排序前: " + Arrays.toString(arr));
sort(arr);
System.out.println("排序後: " + Arrays.toString(arr));
}
}
| 細節 | 說明 |
|---|---|
| 中點計算 | left + ((right - left) >> 1) 避免 (left+right)/2 整數溢出 |
| 穩定性 | 合併時 arr[i] <= arr[j] 先取左邊元素,保證相等元素相對順序不變 |
| 輔助數組 | 每次 merge 分配新數組,簡單但頻繁 GC;優化可在頂層分配一次傳遞複用 |
| 拷貝回寫 | System.arraycopy 為本地方法,比手寫循環快 |
public static void sortIterative(int[] arr) {
int n = arr.length;
int[] temp = new int[n];
for (int width = 1; width < n; width <<= 1) { // 子數組寬度 1,2,4,8...
for (int left = 0; left < n; left += (width << 1)) {
int mid = Math.min(left + width - 1, n - 1);
int right = Math.min(left + (width << 1) - 1, n - 1);
if (mid < right) merge(arr, temp, left, mid, right);
}
}
}
private static void merge(int[] arr, int[] temp, int left, int mid, int right) {
// 同遞歸版 merge 邏輯,但直接使用外部傳入的 temp
// 合併後寫回 arr
}
| 算法 | 時間複雜度 | 空間複雜度 | 穩定 | 適用場景 |
|---|---|---|---|---|
| 歸併排序 | O(n log n) | O(n) | 是 | 外部排序、鏈表排序、需穩定性、數據近似有序 |
| 快速排序 | O(n log n) 平均 | O(log n) | 否 | 通用內存排序、原地排序 |
| 堆排序 | O(n log n) | O(1) | 否 | 嵌入式、實時系統、保證最壞情況 |
| TimSort | O(n log n) | O(n) | 是 | Java Arrays.sort(Object[])、Python sorted() 實際使用 |
歸併排序以穩定、固定 O(n log n) 性能著稱,是外部排序和鏈表排序的首選。Java 中 Arrays.sort() 對對象數組使用 TimSort(歸併+插入優化),對基本類型使用雙軸快排。理解歸併核心邏輯有助於掌握分治思想、優化大數據排序及面試高頻考點。