Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 合并大小相等的堆_Algorithm_Data Structures_Heap - Fatal编程技术网

Algorithm 合并大小相等的堆

Algorithm 合并大小相等的堆,algorithm,data-structures,heap,Algorithm,Data Structures,Heap,有人能解释一下为什么下面合并堆的算法不正确吗 假设我们有两个(最大)堆H1和H2 要合并它们,请执行以下操作: 创建一个键值为负无穷大的人造虚拟节点,并将其放置在根节点处,将H1和H2作为子节点附着。然后做一个O(logn)气泡下降步骤,将根最终交换到叶子位置,在那里它最终被删除。结果结构是一个合并堆 我在维基百科和其他地方都看到过这样的说法:合并两个大小相等的堆是一个θ(n)操作,这与我上面写的内容相矛盾 至少在通常实现堆的情况下(在节点的放置中隐含链接),您似乎几乎忽略的部分(“H1和H2作

有人能解释一下为什么下面合并堆的算法不正确吗

假设我们有两个(最大)堆H1和H2

要合并它们,请执行以下操作:

创建一个键值为负无穷大的人造虚拟节点,并将其放置在根节点处,将H1和H2作为子节点附着。然后做一个O(logn)气泡下降步骤,将根最终交换到叶子位置,在那里它最终被删除。结果结构是一个合并堆


我在维基百科和其他地方都看到过这样的说法:合并两个大小相等的堆是一个θ(n)操作,这与我上面写的内容相矛盾

至少在通常实现堆的情况下(在节点的放置中隐含链接),您似乎几乎忽略的部分(“H1和H2作为子对象连接”)本身就具有线性复杂性

由于堆通常是实现的,因此您有一个线性集合(例如,数组),其中每个元素N都有元素2N和2N+1作为其子元素(例如,对于基于1的数组,元素1的子元素是元素2和3,元素2的子元素是4和5)。因此,在到达合并操作的起点之前,需要将两个堆中的元素交错


如果您从显式链接的二叉树开始(只遵循堆样式规则,而不是二叉搜索树排序),那么您是对的,合并可以用对数复杂度来完成——但我怀疑原始文章是否有意提及这种结构。

如果您将其实现为一棵树,那么您的解决方案是正确的。但正如Jerry提到的,合并基于数组的堆不能在次线性时间内完成


根据合并的频率和大小,我建议您使用虚拟堆。您可以将其实现为堆(带有数组)。经过几次合并后,您可以将多个内部堆懒洋洋地合并到一个大堆中。

我想在这个答案中看到关键字“array”。这个问题显然是一个数组,就像维基百科所说的堆问题一样。@ THITN:是的,我在你评论的时候添加了这个。这很有意义,谢谢。但是,我想知道为什么在将堆实现为链表(又称二叉树)时,会有人想将其实现为数组?@user2097517:首先,它可以节省内存(每个节点需要四个指针才能遍历到父节点,包括子节点和同级节点)。其次,在现代CPU上,它的速度更快(到达另一个节点只需要一点点数学运算,而不是从内存中提取)。最后,大多数堆的使用都不需要合并。IIRC,隐式堆有其性能优势,因为节点尺寸较小:数据移动和缓存占用的绝对减少非常重要!然而,公平地说:显式堆和半堆通常每个节点只有两个指针;如果合并对应用程序很重要,那么您可能应该优先考虑隐式堆。