据我所知,存在二项堆或所谓的可合并堆,用于合并两个堆。我的问题是,不是将这些堆动态地合并到一个堆中,如果我将这两个堆复制到一个大数组然后执行堆构建过程,那么这是一个好方法吗?
因为我不知道如何使用堆操作使用两个堆来创建一个堆。请告诉我,如果这不是一个好方法,或者如果可以的话,请给我一些链接,其中实现了具有合并操作的二项式堆。
答案 0 :(得分:1)
如果你考虑一下,通过丢弃嵌入在其他堆的顺序中的所有信息来创建一个堆可能不是最佳的。最糟糕的情况是,你应该将堆2中的所有项目添加到堆1中,这只是从头开始创建一个全新堆的工作的一半。
但事实上,你可以做得更好方式。合并两个格式良好的堆只需要找到另一个堆树中其中一个根的插入点,然后将其插入该点。不需要进一步的工作,你只做了ln N
工作!有关详细算法,请参阅here。
答案 1 :(得分:1)
它将解决问题,它将为您提供正确的堆 - 但它不会有效。
从头开始创建n
元素的[二进制]堆O(n)
,而merging 2个现有二叉堆是O(logn)
。
答案 2 :(得分:0)
合并2个二项式堆的过程与合并排序中的合并操作非常相似。如果不知道合并 - 堆程序是问题,则以下步骤可能会有所帮助。
重复步骤1到4,直到其中一个堆为空
如果2个堆的头部(二叉树)具有相同的度数,那么您将堆的头部分配给更大的密钥作为具有较小密钥的堆头子项的子项。结果后一堆的头部的程度将增加1,并使前一堆的头部成为其当前头部的下一个元素,如果它们的程度不同,则转到第二步,然后转到步骤4
如果步骤1中后一堆中的头部和下一个二叉树具有相同的度数,则转到步骤3,否则转到步骤1
以与步骤1中相同的方式将头部及其下一个元素组合在一起,并将新的组合二项式树指定为头部,然后转到步骤2.
查看2个堆中哪一个具有较低程度的头部。将此堆的头部指定为其他堆的头部,并将其从最初存在的堆中删除
答案 3 :(得分:0)
Brodal队列和Brodal-Okasaki队列(自举偏斜二项式堆)给出了可合并堆的最佳最坏情况渐近边界,支持O(1)插入,合并和findMin,以及O(log n)deleteMin。 Brodal队列是短暂的,并支持有效的删除和reduceKey。 Brodal-Okasaki队列具有一定的持久性(实际上是纯粹的功能),但不支持delete或decreaseKey。不幸的是,Brodal和Okasaki说这两种实现在实践中都是低效的,并且Brodal认为他的队列太复杂,无论如何都不实用。
Fibonacci堆给出类似的摊销(但不是最坏情况)界限,并且在摊销的背景下可能更有效和实用。配对堆是另一个不错的选择:根据维基百科,它们的确切界限是未知的,但它们在实践中表现非常好。