目标:理解归并排序的核心流程——把大问题拆小,再把两个有序段合并成更大的有序段。
public static void mergeSort(int[] a, int lo, int hi, int[] temp) {
if (lo >= hi) return;
int mid = lo + (hi - lo) / 2;
mergeSort(a, lo, mid, temp);
mergeSort(a, mid + 1, hi, temp);
merge(a, lo, mid, hi, temp);
}
public static void merge(int[] a, int lo, int mid, int hi, int[] temp) {
int i = lo, j = mid + 1, k = lo;
while (i <= mid && j <= hi) {
if (a[i] <= a[j]) temp[k++] = a[i++];
else temp[k++] = a[j++];
}
while (i <= mid) temp[k++] = a[i++];
while (j <= hi) temp[k++] = a[j++];
for (int p = lo; p <= hi; p++) a[p] = temp[p];
}
归并排序可以理解为“分而治之”:先把数组不停对半拆开,再把已经有序的小段按顺序拼回来。
一句话记忆:先拆到不能再拆,再把两个有序段“按小到大”合并回去。
结论:归并排序的最大优势是“性能稳定 + 稳定性好”,主要代价是“额外内存”。
mergeSort(0,7)
├─ mergeSort(0,3)
│ ├─ mergeSort(0,1)
│ │ ├─ mergeSort(0,0) 结束
│ │ └─ mergeSort(1,1) 结束
│ └─ mergeSort(2,3)
│ ├─ mergeSort(2,2) 结束
│ └─ mergeSort(3,3) 结束
└─ mergeSort(4,7)
├─ mergeSort(4,5)
│ ├─ mergeSort(4,4) 结束
│ └─ mergeSort(5,5) 结束
└─ mergeSort(6,7)
├─ mergeSort(6,6) 结束
└─ mergeSort(7,7) 结束
先看全貌,再看细节。每一次都按“全局数组(merge 前)→ 局部合并 → 回写后的全局数组”展示。
最终有序数组
3 条记忆要点