merge-sort

671 字
3 分钟
merge-sort
Warning

含AI生成内容

归并排序(二路归并)#

归并排序是唯一一个既稳定又保证 O(n log n) 的比较排序。代价是需要 O(n) 额外空间。

核心思想#

分治法(Divide and Conquer)

  1. 分解:将数组从中间一分为二
  2. 递归求解:对左右子数组递归地进行归并排序
  3. 合并:将两个已排序子数组合并为一个有序数组
原始: [8,4,5,7,1,3,6,2]
分解: [8,4,5,7] [1,3,6,2]
[8,4] [5,7] [1,3] [6,2]
[8][4] [5][7] [1][3] [6][2]
合并: [4,8] [5,7] [1,3] [2,6]
[4,5,7,8] [1,2,3,6]
[1,2,3,4,5,6,7,8]

代码实现#

Merge 函数#

int *B = (int *)malloc((n + 1) * sizeof(int));
void Merge(int A[], int low, int mid, int high) {
int i, j, k;
for (k = low; k <= high; k++)
B[k] = A[k];
for (i = low, j = mid + 1, k = low; i <= mid && j <= high; k++) {
if (B[i] <= B[j]) // ⭐ <= 保证稳定性
A[k] = B[i++];
else
A[k] = B[j++];
}
while (i <= mid) A[k++] = B[i++];
while (j <= high) A[k++] = B[j++];
}

比较时使用 <= 而非 <,是保证稳定性的关键——相同元素优先取左侧。

MergeSort 递归#

void MergeSort(int A[], int low, int high) {
if (low < high) {
int mid = (low + high) / 2;
MergeSort(A, low, mid);
MergeSort(A, mid + 1, high);
Merge(A, low, mid, high);
}
}

递归分析#

  • 第 1 层:1 个长度为 n 的序列
  • 第 2 层:2 个长度为 n/2 的序列
  • 第 k 层:2^(k-1) 个长度为 n/2^(k-1) 的序列
  • ⌈log₂n⌉ 层(归并趟数)

每层归并操作总共 O(n),总时间 O(n log n)。

复杂度#

指标
最好时间O(n log n)
最坏时间O(n log n)
平均时间O(n log n)
空间O(n)(辅助数组)+ O(log n)(递归栈)
稳定性稳定
归并趟数⌈log₂n⌉

⚠️ 易错:归并排序的每一趟是对相邻有序子表两两合并。第 1 趟后每子表长 2,第 2 趟后长 4……第 k 趟后长 2^k。

与快速排序对比#

对比项归并排序快速排序
最坏时间O(n log n)O(n²)
平均时间O(n log n)O(n log n)
空间O(n)O(log n)
稳定性稳定不稳定
适用场景要求稳定或最坏保证内部排序平均最快

考研高频考点#

  • ⭐ 时间复杂度:所有情况均为 O(n log n)
  • ⭐ 空间复杂度 O(n):需与原数组等长辅助数组
  • ⭐ 归并趟数 ⌈log₂n⌉
  • ⭐ 是稳定的排序算法
  • ⭐ 归并排序 vs 快速排序的对比
  • Merge 操作 <= 保证稳定性的细节
  • 每趟归并的比较次数分析

关联页面#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

merge-sort
https://lingluoa.icu/posts/merge-sort/
作者
lingluoa
发布于
2026-07-07
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
lingluoa
Hello, I'm lingluoa.
公告
欢迎来到我的博客!不定期更新中。
文章目录
标签
站点统计
文章
53
分类
9
标签
75
总字数
175,771
运行时长
0
最后活动
0 天前
站点信息
构建平台
ESA Pages
博客版本
Firefly v6.15.6
文章许可
CC BY-NC-SA 4.0