归并排序 (Merge Sort)

采用分治思想的稳定排序算法,结合二叉树后序遍历理解:先递归处理左右子数组,再合并两个有序数组,时间复杂度稳定为 O(n log n)。

定义

归并排序(Merge Sort)是一种基于**分治算法(Divide and Conquer)**的排序算法。其核心思想是:

先递归地将左右两半子数组排好序,然后在后序位置合并两个有序数组。

归并排序的思维模式可以用二叉树的后序遍历来理解:先处理子问题(左右子树),再合并结果(后序位置)。

核心特性

特性 说明
排序类型 比较排序
时间复杂度 O(n log n),最坏/平均/最好情况都是
空间复杂度 O(n),需要额外数组进行合并
稳定性 稳定排序
排序方式 原地/非原地(典型实现需要额外空间)
思维模式 二叉树后序遍历

基本原理

算法三步骤

  1. 分解(Divide):找到数组中点,将数组分为左右两半
  2. 解决(Conquer):对左右两半分别递归调用归并排序
  3. 合并(Merge):将两个已排序的子数组合并成一个有序数组

递归结构(类比二叉树后序遍历)

sort(nums, lo, hi)
  ├─ if lo == hi: return  (叶子节点,单个元素天然有序)
  ├─ mid = (lo + hi) / 2
  ├─ sort(nums, lo, mid)      // 左子树(前序位置)
  ├─ sort(nums, mid+1, hi)    // 右子树(前序位置)
  └─ merge(nums, lo, mid, hi) // 后序位置:合并左右子树

合并两个有序数组(核心操作)

使用双指针技巧

  • 指针 i 指向左子数组起始位置
  • 指针 j 指向右子数组起始位置
  • 比较 nums[i] 和 nums[j],将较小的放入结果数组
  • 重复直到所有元素处理完毕

稳定性保证:遇到相等元素时,先取左子数组的元素,保持原有相对顺序。

时间复杂度/性能

情况 时间复杂度 说明
最好情况 O(n log n) 每次均匀分割数组
平均情况 O(n log n) 递归深度 log n,每层合并 O(n)
最坏情况 O(n log n) 归并排序时间复杂度稳定,不会出现像快排的 O(n²)
递归深度 O(log n) 每次二分

分析

  • 递归树高度:log n(每次二分)
  • 每层工作量:O(n)(合并操作需要遍历所有元素)
  • 总复杂度:O(n) × O(log n) = O(n log n)

与类似概念对比

维度 归并排序 快速排序 桶排序
遍历模式 二叉树后序遍历 二叉树前序遍历 分桶 + 桶内排序
核心思路 先递归处理左右,再合并 先分区,再递归处理 分配 → 排序 → 合并
时间复杂度 O(n log n) 稳定 O(n log n) 平均,O(n²) 最坏 取决于桶数量和合并方式
空间复杂度 O(n) O(log n) ~ O(n) O(k)
稳定性 稳定 不稳定 取决于桶内排序
是否原地 否(典型实现) 是(原地分区) 取决于实现

注意事项

  • 不是原地排序:典型实现需要 O(n) 额外空间用于合并操作
  • 递归深度:对于非常大的数组,递归深度可能导致栈溢出(可改为迭代版)
  • 适合外部排序:当数据量太大无法一次性加载到内存时,归并排序适合外部排序

应用场景

  • 需要稳定排序的场景
  • 链表排序(链表归并排序可以原地实现)
  • 外部排序(数据量超过内存)
  • 需要稳定 O(n log n) 时间复杂度的场景

经典算法

  • 归并排序本体:分治 + 后序合并
  • 自底向上归并排序:迭代版本,避免递归
  • 链表归并排序:对链表进行原地归并排序
  • 外部归并排序:用于磁盘文件排序

相关概念

  • 排序算法:归并排序是 O(n log n) 排序算法的代表之一
  • 快速排序:对比算法,采用前序遍历思维(先分区再递归)
  • 二叉树:归并排序的思维模式来源(后序遍历)
  • 后序遍历:二叉树后序遍历的应用
  • 递归:归并排序的实现方式
  • 分治算法:归并排序的核心思想
  • 双指针:合并两个有序数组的关键
  • 桶排序:桶排序的合并步骤与归并排序类似

Interactive Graph