| 项目 | 值 |
|---|---|
| 主题 | 归并排序 |
| 核心概念 | 基于分治法,将有序子序列合并为整体有序 |
| 时间复杂度 | $O(n\log_2 n)$(最好/平均/最坏均同阶) |
| 空间复杂度 | $O(n)$(辅助数组) |
| 稳定性 | ✅ 稳定 |
| 难度 | ⭐⭐⭐ |
归并排序(Merge Sort)是基于分治法的排序算法,由 John von Neumann 在 1945 年提出。"归并"是指将两个或多个已经有序的序列合并为一个有序序列的过程。
归并排序的递归树是一棵倒立的完全二叉树,每层归并的时间复杂度为 $O(n)$,共 $\log_2 n$ 层,总时间复杂度为 $O(n\log_2 n)$。
设两个有序子序列为 L[i..m] 和 L[m+1..r],合并步骤:
i 指向第一个子序列开头,j 指向第二个子序列开头,k 指向辅助数组开头L[i] 和 L[j],将较小的元素放入辅助数组 temp[k],相应指针后移n 个元素进行二路归并排序,归并趟数为 $\lceil\log_2 n\rceil$。
// 合并两个有序子序列 A[low..mid] 和 A[mid+1..high]
void Merge(int A[], int low, int mid, int high) {
// 将 A 中元素复制到辅助数组 temp
for (int k = low; k <= high; k++)
temp[k] = A[k];
int i = low, j = mid + 1, k = low;
// 比较两个子序列的元素,按顺序放入原数组
while (i <= mid && j <= high) {
if (temp[i] <= temp[j]) // 注意:<= 保证稳定性
A[k++] = temp[i++];
else
A[k++] = temp[j++];
}
// 处理剩余元素
while (i <= mid) A[k++] = temp[i++];
while (j <= high) A[k++] = temp[j++];
}
// 归并排序(递归实现)
void MergeSort(int A[], int low, int high) {
if (low < high) {
int mid = low + (high - low) / 2; // 从中间划分
MergeSort(A, low, mid); // 对左半部分归并排序
MergeSort(A, mid + 1, high); // 对右半部分归并排序
Merge(A, low, mid, high); // 合并两个有序子序列
}
}
// 初始化调用
void Sort(int A[], int n) {
temp = (int *)malloc(n * sizeof(int));
MergeSort(A, 0, n - 1);
free(temp);
}
对序列 {49, 38, 65, 97, 76, 13, 27} 进行归并排序。先递归分解为单元素,再自底向上合并;下面以最后一步合并为例:
左半已排好 [38, 49, 65, 97],右半已排好 [13, 27, 76],合并过程:
[13][13, 27][13, 27, 38][13, 27, 38, 49][13, 27, 38, 49, 65][13, 27, 38, 49, 65, 76][13, 27, 38, 49, 65, 76, 97]这正是右侧交互动画演示的内容。
| 情况 | 时间复杂度 | 说明 |
|---|---|---|
| 最好情况 | $O(n\log_2 n)$ | 序列有序时 |
| 平均情况 | $O(n\log_2 n)$ | 随机输入 |
| 最坏情况 | $O(n\log_2 n)$ | 序列逆序时 |
空间复杂度为 $O(n)$
归并排序是稳定的排序算法。
原因:在合并过程中,当两个子序列中的元素相等时(temp[i] == temp[j]),我们总是先取第一个子序列的元素(使用 <= 比较),这保证了相等元素的相对顺序不变。
< 而不是 <= → 会导致不稳定<= 比较保证稳定性(暂无关联知识点)