从堆中弹出所有n个元素的复杂性是什么?

问题描述

要构建堆,经常会误认为O(n log n)是严格的上限,但实际上是O(n)。

我想说的是,从堆中弹出所有n元素是O(n log n),但是基于我对构建堆的复杂性的了解,我很犹豫,我认为这可能出于相同的原因,将O设为O(n)。

这正确吗?

每次弹出时,我们需要找到一个新的根,然后heapify函数将花费O(h)时间,其中h是二叉树的高度。对于像堆使用的平衡二叉树,h = log_2(n)。但是,每次弹出节点的数量会逐个减少,因此h应该减少。

所以如果我要计算复杂度,我会做类似的事情

O(log_2(n) + log_2(n-1) + ... + log_2(1))
= O(log_2(n * (n-1) * ... * (1))
= O(log_2(n^n)) 
= O(n log_2(n)

但这是实际的严格上限吗?

解决方法

想象一下,有一种方法可以在时间O(n)内从堆中弹出n次。这将为您提供基于比较的排序算法,该算法在时间O(n)下运行,如下所示:

  • 使用heapify在时间O(n)内构建堆。
  • 使用O(n)时间算法进行n次弹出。

但是,这是不可能的,因为所有基于比较的排序算法平均且在最坏的情况下以时间Ω(n log n)运行。

实际上,此参数表明,n次弹出的代价必须是最坏情况下的运行时间Ω(n log n),这样在最坏情况下上限就很紧。