【问题标题】:Why we build max heap from bottom up instead from top bottom为什么我们自下而上而不是自上而下构建最大堆
【发布时间】:2021-10-25 15:10:00
【问题描述】:

问题:为什么我们希望BUILD-MAX-HEAP第2行的循环索引i⌊length[A]/2⌋减少到1而不是从1 增加到@ 987654334@?

算法:(由《算法简介》一书提供):

我尝试使用以下图纸来展示这一点。

方法 1:如果我们以相反的方式将构建堆从 1 应用到数组 A = <5,3,17,10,84>⌊length[A]/2⌋,我们会:

方法 2:如果我们从 ⌊length[A]/2⌋ 以相反的方式应用构建堆并减少到数组 A = <5,3,17,10,84>1,我们将:

问题:我看到在这两种情况下,父级大于其子级的堆属性都得到了维护,所以我不明白为什么一个解决方案会说会有这样的问题, “我们将不允许调用 MAX-HEAPIFY,因为它会使子树成为最大堆的条件失败。也就是说,如果我们以 1 开头,则无法保证A[2]A[3] 是最大堆的根。”

【问题讨论】:

  • MAX-HEAPIFY 利用了 LEFT 和 RIGHT 都是有效堆这一事实。如果您以i=1 开头,则该假设无效。在 MAX-HEAPIFY(A, 1) 之后,A[1] 中的值要么是 A[1],要么是 A[2],要么是 A[3],并且以后的任何迭代都不会更改该值。但是堆中的最大值可能不是前三个之一。在您的示例中,第一个 MAX-HEAPIFY(A, 1) 产生 ,之后没有任何变化 A[1],所以根是 17。我不知道 84设法在您的方法 1 图中到达那里。
  • @RaymondChen。很明确的答案。我假设我是实时插入数组,所以每次添加新元素时我都会Heapify,这和你说的基本相同,所以我没有意识到我在方法1中使用Heapify Up方法. 在第二种方法中,我在插入所有元素后进行了 Heaify。所以两者都是基于 Heapify Up 的事实,所以我什至没有关注问题中提出的 Heapify。
  • 如果您一次插入一个元素,那么这是一种不同的算法。 BUILD-MAX-HEAP 用于从非堆数组创建堆。如果您想将单个元素添加到已经有效的堆中,这是一个不同的操作,可能称为 INSERT-HEAP 之类的操作。一次添加一个项目是discussed here

标签: algorithm heap


【解决方案1】:

问题是你只能依靠MAX_HEAPIFY 来完成它的工作,当以 i 为根的子树在任何地方都遵循堆属性除了 可能对于根值(在 ​​i 处)本身,可能需要筛选。 MAX_HEAPIFY 的工作只是将根的值移动到正确的位置。它无法修复任何其他违反堆属性的行为。但是,如果保证 i 下面的树的其余部分遵循堆属性,那么您可以确定 i 处的子树将是 @ 之后的堆987654323@已运行。

所以如果你从顶部节点开始,那么谁知道你会得到什么......树的其余部分不应该服从堆属性,所以MAX_HEAPIFY 不会(必然)传递堆。而且以自上而下的方式继续工作也无济于事。

如果我们采用示例树并执行 forward 循环替代方案,那么我们首先在这棵树上调用 MAX_HEAPIFY(1)

       5
      / \
     3   17
    / \
  10   84

...然后 5 将与 17 交换(在位置 3),然后我们将在该节点上递归调用 MAX_HEAPIFY(3),这将什么都不做。所以我们会得到:

       17
      / \
     3   5
    / \
  10   84

接下来,我们调用 MAX_HEAPIFY(2),它将 3 与 84 交换:

       17
      / \
     84  5
    / \
  10   3

在值为 3 的节点上再次进行递归调用,但这不会做任何事情。

这是 forward 循环替代方案中MAX_HEAPIFY 的最后一次调用......我们可以看到值 84 没有机会一直找到它的顶部属于。

【讨论】:

  • 非常详细和清晰的回答,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-30
  • 2021-10-30
  • 2021-10-16
  • 2010-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多