板子:归并排序
从中间对半分,左右两半分别排好,再用双指针合并成一个有序段。分割点永远在正中间,和数据无关,所以最好、最坏、平均都是
。
代码
int *B; // 辅助数组(教材写法:全局指针,排序前申请 n 个)
void Merge(int A[], int low, int mid, int high) { // 把有序的 A[low..mid] 和 A[mid+1..high] 合并
for (int k = low; k <= high; k++) B[k] = A[k]; // 先把这一段整体复制到 B
int i = low, j = mid + 1, k = low; // i、j 分别扫描 B 的前后两段,k 是写回 A 的位置
while (i <= mid && j <= high)
A[k++] = B[i] <= B[j] ? B[i++] : B[j++]; // 用 <=:相等时先取前一段的,保证稳定
while (i <= mid) A[k++] = B[i++]; // 剩下的直接接上(两个 while 只会执行一个)
while (j <= high) A[k++] = B[j++];
}
void MergeSort(int A[], int low, int high) {
if (low >= high) return; // 只有一个元素:已经有序
int mid = (low + high) / 2; // 从中间分成两半
MergeSort(A, low, mid); // 左半 [low, mid]
MergeSort(A, mid + 1, high); // 右半 [mid+1, high]
Merge(A, low, mid, high); // 两半合并
}
// 调用:B = (int *)malloc(n * sizeof(int)); MergeSort(A, 0, n - 1); free(B);复杂度:时间最好、平均、最坏都是 B)。稳定。
关键边界
| 代码 | 为什么 |
|---|---|
左半是 [low, mid],右半是 [mid+1, high] | mid 归左半。写成 [low, mid-1] 和 [mid, high] 的话,两个元素时 mid == low,右半还是原区间,会无限递归 |
B[i] <= B[j] 带等号 | 相等时先取前一段的元素,相对次序不变,所以归并排序稳定 |
先复制到 B 再写回 A | 直接在 A 上合并会覆盖还没比较的元素 |
B 只申请一次 | 在 Merge 里每次 malloc 也对,但频繁申请和释放很慢。教材用的是全局数组 |
易错点
- 归并排序是唯一一个平均
而且稳定的排序算法,选择题的直接答案。 - 二路归并的趟数是
,手算题问「第 趟以后的序列」时,按长度 的有序段两两合并。 Merge的写法和 有序表合并 是同一个骨架。
链接
- 📕 返回:数据结构代码板子
- ⬅️ 上一篇:堆排序
- ➡️ 下一篇:折半插入排序与希尔排序
- 🔗 8.5 归并排序、基数排序和计数排序