为啥自上而下的堆构建方法比自下而上的方法效率低,即使它的增长顺序比 O(n) 低 O(log n)?

Posted

技术标签:

【中文标题】为啥自上而下的堆构建方法比自下而上的方法效率低,即使它的增长顺序比 O(n) 低 O(log n)?【英文标题】:Why is the top down approach of heap construction less efficient than bottom up even though its order of growth is lower O(log n) over O(n)?为什么自上而下的堆构建方法比自下而上的方法效率低,即使它的增长顺序比 O(n) 低 O(log n)? 【发布时间】:2016-07-13 14:37:29 【问题描述】:

O(n) 顺序的堆构造自下而上的方法如何? Anany Levitin 在他的书中说,与 O(log n) 的自顶向下方法相比,这更有效。为什么?

【问题讨论】:

***.com/questions/9755721/… 【参考方案1】:

这对我来说似乎是一个错字。

构建堆有两种标准算法。第一种是从一个空堆开始,一次一个地重复插入元素。每个单独的插入需要时间 O(log n),因此我们可以将这种堆构建方式的成本上限设置为 O(n log n)。事实证明,在最坏的情况下,运行时间是 Θ(n log n),如果您以反向排序的顺序插入元素,就会发生这种情况。

另一种方法是 heapify 算法,它直接构建堆,方法是从自己的二进制堆中的每个元素开始,并逐步将它们合并在一起。无论输入如何,该算法都在 O(n) 时间内运行。

第一个算法需要时间 Θ(n log n) 的原因是,如果你看一下被插入的元素的后半部分,你会发现它们中的每一个都被插入到一个高度为 Θ 的堆中(log n),因此每次冒泡的成本可能很高。由于有 n / 2 个元素,并且每个元素都可能需要时间 Θ(log n) 来插入,因此最坏情况的运行时间是 Θ(n log n)。

另一方面,heapify 算法将大部分时间花在小堆上。一半的元素插入到高度为 0 的堆中,四分之一插入到高度为 1 的堆中,八分之一插入到高度为 2 的堆中,等等。这意味着大部分工作都用于将元素插入到小堆中,这明显更快。

【讨论】:

heapify 算法在插入方面是否比自顶向下方法效率低?因为自上而下的方法需要 O(log n) 进行插入,但对于 heapify,首先我们按顺序插入元素,然后 heapify 是 O(n)。因此,如果要一个接一个地插入太多元素,heapify 将充当 O(n2),其效率低于自顶向下的 O(n log n)? 它们旨在做不同的事情。 heapify 算法适用于您已经拥有要放入堆中的所有元素的情况,如果您事先不知道您将拥有多少元素或它们是什么,则另一种方法有效.如果一次只获取一个元素,那么 heapify 算法就没有那么好了。 这有帮助。谢谢你的解释。 @geek_code 如果您有兴趣查找更高级的数据结构,您可能想查看二项式堆,即使您不这样做,它也需要时间 O(n) 来执行 n 次插入事先不知道会有多少元素。 在“在最坏的情况下,运行时间是 Θ(n log n)”这一行中,为什么要使用 theta 来表示最坏的情况。 AFAIK big O 用于表示最坏的情况。抱歉这个愚蠢的问题,如果是的话,但请告诉我“为什么”。【参考方案2】:

如果你认为交换是你的基本操作-

在自顶向下构造中,首先构造树并在节点上调用 heapify 函数。最坏的情况是交换 log n 次(将元素筛选到树的顶部,树的高度为 log n)对于所有 n/2 叶节点。这导致 O(n log n) 上限。

在自下而上的构造中,您假设所有叶节点在第一遍中都是有序的,因此现在仅在 n/2 个节点上调用 heapify。在每个级别,可能的交换数量都会增加,但发生交换的节点数量会减少。

例如—— 在叶节点正上方的级别, 我们有 n/4 个节点,每个节点最多可以有 1 个交换。 在它的父级,我们有, n/8 个节点,每个节点最多可以有 2 个交换,依此类推。 总而言之,我们将得出自下而上构建堆的 O(n) 效率。

【讨论】:

【参考方案3】:

它通常指解决问题的方法。尤其是在计算机科学算法方面。

自上而下:

把整个问题分解成两个或多个部分。 找到这些部分的解决方案。 如果这些部分变得太大而无法作为一个整体解决,请将它们进一步拆分并找到这些子部分的解决方案。 成功解决所有部分后,根据由此创建的子问题层次合并解决方案。

在常规的heapify()中,我们从上到下对每个节点进行两次比较,找出三个元素中最大的一个:

    有左孩子的父节点 第一次比较中的较大节点与第二个子节点

自下而上:

将问题分解成尽可能小的(和实际的)部分。 寻找这些小子问题的解决方案。 合并您迭代(一次又一次)获得的解决方案,直到您将所有解决方案合并以获得“大”问题的最终解决方案。方法的主要区别是拆分与合并。您要么从大处开始并根据需要“向下”拆分,要么从最小处开始并“向上”合并到最终解决方案。

另一方面,自下而上的堆排序仅比较两个孩子并跟随较大的孩子到树的末端(“自上而下”)。从那里,算法回到树根(“自下而上”)并搜索大于根的第一个元素。从这个位置开始,所有元素都向根移动一个位置,根元素被放置在已经变得空闲的字段中。

【讨论】:

以上是关于为啥自上而下的堆构建方法比自下而上的方法效率低,即使它的增长顺序比 O(n) 低 O(log n)?的主要内容,如果未能解决你的问题,请参考以下文章

数据仓库架构

怎么用css的方法将门打开后展示灯笼自上而下的动画?

mysql innodb建立普通索引怎么写

BI之SSAS完整实战教程3 -- 创建第一个多维数据集.docx

Mysql Innodb存储引擎 select count 太慢,怎么优化

Java模块化开发