【问题标题】:complexity of heap data structure堆数据结构的复杂性
【发布时间】:2020-01-03 16:04:22
【问题描述】:

我正在尝试在堆排序算法中计算构建堆的运行时间

BUILD-HEAP(A) 
heapsize := size(A); 
  for i := floor(heapsize/2) downto 1 
    do HEAPIFY(A, i); 
  end for 
END 

时间为什么是线性的背后的基本思想是由于 heapify 的时间复杂度取决于它在堆中的位置。节点为叶子节点(至少占一半节点)需要O(1)时间,根节点需要O(logn)时间。

O(n) 时间可以通过解决以下问题来证明:

image by HostMath

我在这里理解的 O(h) 意味着每个节点的 heapify 的最坏情况,所以 height=ln n 如果节点在根中,例如 heapify 节点 2,1,3 它需要 ln_2 3 =1.5 的高度根节点 2 的值为 1,因此对 HEAPIFY 的调用为 ln_2 n=height = O(h)

BUILD-HEAP(A) 
heapsize := size(A); 
  for i := floor(heapsize/2) downto 1 
    do HEAPIFY(A, i); 
  end for 
END 




 suppose this is the tree

       4    .. height2
      / \ 
    2   6  .. height 1
    /\   /\  
  1 3 5 7  .. height 0

快速浏览上述算法表明运行时间为 O(nlg(n)),因为每次调用 Heapify 的成本为 O(lg(n)),而 Build-Heap 的调用时间为 O(n)。 这个上限虽然是正确的,但并不是渐近紧的。 构建二叉堆的时间复杂度为 O(n)。

我试图理解,heapsize/2 意味着 for 循环仅调用 HEAPIFY heapsize/2 次。在上面的树中,heapsize=7, 7/2= 3 所以根是 {1,2,6} 所以 n/2

每次调用 HEAPIFY 都会再次调用 HEAPIFY 直到到达每个根的最后一个叶子, 例如,2 将调用 heapify 1 次,6 将调用 heapify 1 次,1 将调用 heapify 2 次。所以树的高度是ln n。我说的对吗?

那么复杂度将是 O(n/2 * ln n) = O(n ln n)

哪一个是对的? O(n ln n) 还是 O(n)?

我怎样才能得到 O(n)?

我在阅读此作为参考,如果我错了,请纠正我,谢谢! https://www.growingwiththeweb.com/data-structures/binary-heap/build-heap-proof/ 这是我使用的参考资料,我也在 CLRS 书中读到了这一点

https://www.hostmath.com/Show.aspx?Code=ln_2%203

【问题讨论】:

  • 您的问题难以辨认,尤其是在您使用“$”的地方。
  • 不幸的是 Latex 公式没有被渲染(duh,正确的)。请参阅 StackOverflow 元问题 LaTeX on Stack Overflow: any way to include a formula?。您可能希望将您的问题迁移到 comp-sci s.o.,cs.stackexchange.com
  • @Richard 谢谢你的编辑!我试图在您建议的链接中使用chart.googleapis,但没有显示仅链接的图片?我也尝试添加图像,但我的声誉低于 10,所以我无法添加图像。我也尝试HostMath.com/Show.aspx?Code=ln_2%203 放这个链接但没有显示图片?
  • 我还没有尝试过 google apis,请尝试使用 hostmath.com 进行在线 Latex 渲染。 Rep 已经很接近了,所以猜想您可以稍后通过图像编辑重新访问,或者在 comp sci 上重新发布,或者在代码格式的文本中以最佳方式模拟公式(反引号内的东西 code format
  • @Richard 谢谢,对于主机数学,您是否复制了外部 URL 并粘贴了 URL 链接?我试过了,但只显示了网址,没有图像?例如hostmath.com/Show.aspx?Code=ln_2%203

标签: data-structures time-complexity binary-tree big-o heap


【解决方案1】:

复杂度是 O(n) 这就是原因。假设树有 n 个节点。由于堆是近乎完全的二叉树(根据 CLRS),所以后半部分节点都是叶子;所以,没有必要把它们堆起来。现在剩下的一半。我们从位置 n/2 的节点开始并向后走。在 heapifying 中,一个节点只能向下移动,因此,正如您所说,完成该节点的 heapify 最多需要节点交换操作的高度。

对于 n 个节点,我们最多有 log n 个级别,其中级别 0 具有根,级别 1 最多具有 2 个节点,依此类推:

level 0:              x
.                    / \  
level 1:            x   x
.
level log n:    x x x x x x x x 

所以,我们有以下内容:

logn-1 级别的所有节点最多需要 1 交换才能被堆化。 (这里最多 n/2 个节点)

logn-2 级别的所有节点最多需要 2 次交换才能被堆化。 (这里最多 n/4 个节点)

....

级别 0 的所有节点最多需要 logn 交换才能被堆化。 (这里最多1个节点,即根)

所以,总和可以写成:

(1 x n/2 + 2 x n/4 + 3 x n/8 + ... + log n x n/2^logn)

我们把 n 分解出来,我们得到:

n x (1/2 + 2/4 + 3/8 + ... + log n/2^logn)

现在总和 (1/2 + 2/4 + 3/8 + ... + log n/2^logn) 总是 Sigma i over 2^i);因此,我们感兴趣的上述总和总是

【讨论】:

  • 非常感谢!!所以它是 height=log n* total nodes at height ,但是当您说最多 n/2 个节点时,例如在级别 1 中,从根开始总共有 n=3 个节点,最多 n/2=3/ 2 =1.5 = 2 还是 1?
  • @devss 我说在级别 logn 中最多 n/2 个节点 - 1。目标是分别计算每个级别的工作量。当我们在级别上升时,节点数除以 2。随着我们下降,每个级别的节点数乘以 2。因此,级别 0、1 节点。 1 级,2 个节点。 3 级,4 个节点。
  • 谢谢你的解释!!但是我仍然感到困惑,当您说在 logn -1 中最多 n/2 个节点时,例如在级别 3 中有来自根的 7 个节点,所以在级别 log 7 -1 中最多 7/2 =3.5(?)但是有是四个节点(?)
  • @devss 我明白了。所以,假设有 n=7 个节点。 0级有1个节点,1级有2个节点,2级有4个节点。因此,logn - 1 实际上是这棵树中的第 1 级,它有 2 个节点,并且 2 小于或等于 (
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-29
  • 2020-07-16
相关资源
最近更新 更多