前言
非递归实现的归并排序,通常被称为'自底向上'(Bottom-Up)版本。与递归版本不同,它不依赖栈回溯拆分数组,而是直接从长度为 1 的最小有序子序列开始,两两合并,步长翻倍(1→2→4→8...),直到覆盖整个数组。
核心思路
将递归逻辑改写为循环结构是非递归实现的关键。递归是'先拆分后合并',而非递归则是'只合并'。
为什么不用栈模拟?
如果仅用栈模拟递归的拆分过程,我们只能记录区间,却容易丢失'合并'的上下文。例如,当栈弹出 [0, 3] 拆分为 [0, 1] 和 [2, 3] 后,原区间信息被丢弃。当子任务处理完毕回到上一层时,程序不知道需要将这两个结果段合并回去。因此,自底向上的迭代法更直接:显式控制步长 gap,按顺序合并相邻块。
算法流程
- 初始化:设步长
gap = 1。 - 合并:将数组视为由多个长度为
gap的有序子数组组成,两两合并。 - 倍增:每轮结束后
gap *= 2。 - 终止:当
gap >= n时,整个数组有序。
想象面前有一排乱序的扑克牌:先把相邻的每张牌看作一组,两两合并成有序的 2 张;再把这 2 张看作一组,合并成 4 张……直到无法再分或全部合并完成。
实现细节演示
假设数组为 [10, 6, 7, 1, 3, 9, 4, 2],长度 n = 8。
第一轮:gap = 1
此时数组被视为 8 个长度为 1 的子数组。相邻两两合并:
[10]与[6]合并 →[6, 10][7]与[1]合并 →[1, 7][3]与[9]合并 →[3, 9][4]与[2]合并 →[2, 4]
结果:[6, 10, 1, 7, 3, 9, 2, 4]。此时数组变为两两有序。
第二轮:gap = 2
将相邻的长度为 2 的有序子数组合并:
[6, 10]与[1, 7]合并 →[1, 6, 7, 10][3, 9]与[2, 4]合并 →[2, 3, 4, 9]
结果:[1, 6, 7, 10, 2, 3, 4, 9]。此时数组变为四四有序。
第三轮:gap = 4
最后合并两个长度为 4 的有序部分:
[1, 6, 7, 10]与[2, 3, 4, 9]合并 →[1, 2, 3, 4, 6, 7, 9, 10]
排序完成。
边界问题处理
归并排序的逻辑基于完全二叉树结构,理想情况下数组长度是 2 的幂次。但在实际应用中,N 往往不是 2 的整数次幂,这会带来边界越界风险。
常见情况
- 左半区间落单:当 时,说明右半区间不存在,无需合并,直接跳过。


