排序算法之:最小比较数排序(Ford-Johnson Merge-Insertion Sort)的递推关系与比较次数下界分析
1. 问题描述
我们熟知比较排序算法的时间复杂度下界是 \(O(n \log n)\),但针对具体的 \(n\),是否存在一个确定性算法,使得对任意长度为 \(n\) 的数组排序所需的比较次数最少?
Ford-Johnson 算法(又称 Merge-Insertion Sort)是已知的、在实际 \(n\) 下能逼近理论最小比较次数的算法之一。
本题目要求:
- 解释 Ford-Johnson 算法的基本步骤。
- 推导其比较次数的递推关系。
- 分析该递推关系如何给出算法在最坏情况下的比较次数下界。
2. 算法基本思想
Ford-Johnson 算法结合了合并排序与二分插入排序的优点,分三个阶段:
阶段一:配对与比较
- 将 \(n\) 个元素两两配对,得到 \(\lfloor n/2 \rfloor\) 对。
- 对每对元素进行一次比较,将较小的放入集合 \(S\),较大的放入集合 \(L\)(若 \(n\) 为奇数,多出的一个元素暂存)。
阶段二:递归排序较大者集合 \(L\)
- 对集合 \(L\) 递归应用 Ford-Johnson 算法排序(因为 \(L\) 的大小约为 \(n/2\))。
- 排序后,\(L\) 中的元素按顺序记为 \(l_1 < l_2 < \dots < l_{\lfloor n/2 \rfloor}\)。
阶段三:二分插入较小者集合 \(S\)
- 将 \(S\) 中的元素依次插入已排序的 \(L\) 序列中,但插入顺序经过精心设计:
按照 \(S\) 中元素在原配对中对应的 \(l_i\) 的下标顺序插入,具体顺序由一组预定义的“插入点”决定(称为 Jacobsthal 数序列)。
3. 比较次数的递推关系
设 \(F(n)\) 表示 Ford-Johnson 算法对 \(n\) 个元素排序所需的最坏情况比较次数。
步骤分析:
- 阶段一:配对比较次数为 \(\lfloor n/2 \rfloor\)。
- 阶段二:递归排序 \(L\),其大小为 \(\lceil n/2 \rceil\),比较次数为 \(F(\lceil n/2 \rceil)\)。
- 阶段三:插入 \(S\) 中的元素。
- 已排序的 \(L\) 序列长度为 \(m = \lceil n/2 \rceil\)。
- \(S\) 的大小为 \(\lfloor n/2 \rfloor\)。
- 关键:每个 \(s_i\) 插入时,已知其对应的 \(l_i\) 在 \(L\) 中的位置,因此只需在 \(l_i\) 之前的部分进行二分查找(因为 \(s_i < l_i\)),查找范围长度逐渐增加。
- 通过 Jacobsthal 顺序安排插入,使得每次二分查找的成本最小化。
递推公式推导:
插入第 \(k\) 个 \(s\) 元素时,二分查找的比较次数约为 \(\lceil \log_2 (k+1) \rceil\)。
对 \(\lfloor n/2 \rfloor\) 个插入操作,总比较次数近似为:
\[\sum_{k=1}^{\lfloor n/2 \rfloor} \lceil \log_2 (k+1) \rceil \]
因此递推关系为:
\[F(n) = \lfloor n/2 \rfloor + F(\lceil n/2 \rceil) + \sum_{k=1}^{\lfloor n/2 \rfloor} \lceil \log_2 (k+1) \rceil \]
其中 \(F(0)=0, F(1)=0\)。
4. 递推关系的求解与下界分析
上述递推关系可以进一步简化。
记 \(n = 2^m\) 或近似分析,可得:
\[F(n) \approx \frac{n}{2} + F\left(\frac{n}{2}\right) + \sum_{k=1}^{n/2} \lceil \log_2 (k+1) \rceil \]
而 \(\sum_{k=1}^{n/2} \lceil \log_2 (k+1) \rceil \approx \frac{n}{2} \log_2 n - n + O(\log n)\)。
代入递推并展开:
\[F(n) \approx \frac{n}{2} + F\left(\frac{n}{2}\right) + \frac{n}{2} \log_2 n - n + O(\log n) \]
合并常数项后递归展开,可得:
\[F(n) \approx n \log_2 n - 1.415n + O(\log n) \]
精确分析表明,Ford-Johnson 算法在最坏情况下比较次数为:
\[F(n) = n \log_2 n - n \cdot \left( \log_2 \left( \frac{4}{3} \right)^{-1} \right) + O(\log n) \]
其中常数约为 \(1.415\)。
5. 与理论下界的对比
比较排序的决策树模型给出最坏情况下比较次数下界为 \(\lceil \log_2 n! \rceil\)。
利用斯特林公式:
\[\log_2 n! = n \log_2 n - n \log_2 e + O(\log n) \approx n \log_2 n - 1.443n + O(\log n) \]
Ford-Johnson 算法的比较次数(约 \(n \log_2 n - 1.415n\))与此下界(约 \(n \log_2 n - 1.443n\))相差仅约 \(0.028n\),即非常接近理论最优。
6. 关键点总结
- 配对策略:减少递归规模至一半。
- 递归排序较大者:保证插入时的有序基准。
- Jacobsthal 顺序插入:最小化二分查找的总比较次数。
- 递推关系:精确刻画了比较次数增长。
- 接近最优:常数项差距极小,说明 Ford-Johnson 在确定性算法中几乎是最优的。
7. 实际应用与限制
- 优点:比较次数极少,适合比较成本高的场景(如复杂键值比较)。
- 缺点:实现复杂,需要额外空间管理配对关系,插入顺序的计算也增加开销。
- 现代意义:更多作为理论研究的案例,实际中快速排序、TimSort 等因缓存友好性更常用。
通过以上步骤,我们完整理解了 Ford-Johnson 算法的设计原理、递推关系的建立与求解,以及其与比较排序理论下界的紧密关系。