所以我做了一些挖掘自己,看起来这个结果实际上是最近的!我能找到的第一个下界证明是从 1992 年开始的,尽管堆排序本身是在 1964 年发明的。
正式的下界证明归功于 Schaffer 和 Sedgewick 的“堆排序分析”论文。这是一个略为解释的证明版本,省略了一些技术细节。
首先,假设对于某个 k,n = 2 k - 1,这保证了我们有一个完整的二叉堆。稍后我将展示如何单独处理这种情况。因为我们有 2 k - 1 个元素,所以堆排序的第一遍将在 Θ(n) 中建立一个高度为 k 的堆。现在,考虑这个堆的前半部分出队,它删除了 2 k-1堆中的节点。第一个关键观察结果是,如果您使用起始堆,然后在此处标记实际上最终出队的所有节点,它们将形成堆的子树(即,每个出队的节点都有一个也出队的父节点)。您可以看到这一点,因为如果不是这种情况,那么尽管节点本身已出列,但某些节点的(较大的)父节点并未出列,这意味着值是无序的。
现在,考虑这棵树的节点是如何分布在堆中的。如果您将堆的级别标记为 0、1、2、...、k - 1,那么在级别 0、1、2、...、k - 2 中会有一些这些节点(即除了树的底层之外的所有内容)。为了让这些节点从堆中出列,它们必须向上交换到根节点,并且一次只能向上交换一层。这意味着降低堆排序运行时间的一种方法是计算将所有这些值带到根所需的交换次数。事实上,这正是我们要做的。
我们需要回答的第一个问题是——最大的 2 k-1个节点中有多少不在堆的底层?我们可以通过矛盾证明这不大于 2 k-2 。假设在堆的底层至少有 2 k-2 + 1 个最大节点。那么这些节点的每个父节点也必须是级别 k - 2 中的大节点。即使在最好的情况下,这意味着级别 k - 2 中必须至少有 2 k-3 + 1 个大节点,这意味着在第 k - 3 层中至少有 2 k-4 + 1 个大节点,等等。总结所有这些节点,我们得到有 2 k-2 + 2 k-3 + 2 k-4 + ... + 20 + k 个大节点。但是这个值严格大于 2 k-1,这与我们在这里只使用 2 k-1个节点的事实相矛盾。
好的……我们现在知道底层最多有 2 k-2 个大节点。这意味着在前 k-2 层中必须至少有 2 k-2个大节点。我们现在要问——在所有这些节点上,从那个节点到根的距离的总和是多少?好吧,如果我们有 2 k-2个节点位于完整堆的某个位置,那么其中最多 2 k-3个节点可以位于前 k - 3 个级别,因此至少有 2 k-2 - 2 k- 3 = 2 k-3级 k - 2 重节点。因此,需要执行的交换总数至少为 (k - 2) 2 k-3。由于 n = 2 k-1,k = Θ(lg n),所以这个值是 Θ(n lg n) 需要的。