Data structures 二进制堆与d元堆

Data structures 二进制堆与d元堆,data-structures,heap,binary-heap,Data Structures,Heap,Binary Heap,我读到过二进制堆在执行最小删除操作时更快,而d元堆在执行降低优先级操作时更快(虽然我不知道为什么),但我还读到过,与二进制堆相比,4元堆在这两个操作上都更快 那么,我什么时候使用二进制堆,什么时候使用d元堆?我如何决定d元堆的d应该是什么呢?这里有一些不同的因素,我相信,这些因素使您所做的所有陈述都可能是正确的 为了了解原因,让我们首先考虑d进制堆中的decrease键是如何工作的(我们不需要单独讨论二进制堆,因为二进制堆只是一个2进制堆)。在执行减少键时,我们更改树中节点的优先级,然后重复将其

我读到过二进制堆在执行最小删除操作时更快,而d元堆在执行降低优先级操作时更快(虽然我不知道为什么),但我还读到过,与二进制堆相比,4元堆在这两个操作上都更快


那么,我什么时候使用二进制堆,什么时候使用d元堆?我如何决定d元堆的d应该是什么呢?

这里有一些不同的因素,我相信,这些因素使您所做的所有陈述都可能是正确的

为了了解原因,让我们首先考虑d进制堆中的decrease键是如何工作的(我们不需要单独讨论二进制堆,因为二进制堆只是一个2进制堆)。在执行减少键时,我们更改树中节点的优先级,然后重复将其与其父节点交换,直到它到达树的根节点,或者其优先级最终小于其父节点的优先级。在最坏的情况下,我们必须进行交换的次数由d元堆的高度给出。由于d元堆的每一层中的节点数在每一步都以指数形式增长d倍,因此d元堆的高度为O(logdn)=O(logn/logd)。这意味着,如果增加d的值,d元堆的高度将降低,因此减少键和插入将花费更少的时间。如果您考虑一个极端情况,如果您有一个10100位的堆,那么树中的层数将比二进制堆中的层数少大约100倍,因此减少键或插入将快大约100倍

另一方面,考虑一下出列操作将如何工作。要执行出列,我们交换根的最后一个叶,然后重复执行以下操作:扫描当前节点的所有子节点,如果其中任何子节点小于当前节点,则将当前节点与其最小的子节点交换。这些迭代中的每一个都需要O(d)总比较来找到最小的子级,迭代次数由树中的层数给出,我们前面看到的是O(logn/logd)。这意味着d元堆中的出列成本为O(d log n/log d)。由于d的增长速度比logD快得多(事实上是指数级的),随着d的增加,排队的渐近和实际成本开始上升。例如,在一个10100元的堆中,您可能需要在每个步骤中将每个节点与10100个子节点进行比较,这将花费很长时间!因此,随着d变得越来越大,d元堆的出列速度往往比二进制堆慢得多

现在进入最后一个问题:根据这里的信息,4元堆的性能如何可能优于二进制堆?我将非常诚实地说,我不知道这是否是真的,但它(a)可能取决于硬件,(b)不会让我感到惊讶。请记住,前面的所有分析都试图通过查看堆中的层数和交换次数等数量来限制d元堆操作的成本。然而,这忽略了许多其他因素,例如寻找父母和孩子的成本以及参考地点。对于其中的第一个,请注意,在d元堆中,可以通过将索引除以d来查找父节点。对于二的完美幂d,可以通过简单、廉价的位移位实现(因为n/2k=n>>k)。对于奇数或不是二的幂的数,这需要除法,这(在某些体系结构中)比位移位更昂贵。此外,还存在引用位置的影响。如今的计算机在内存中有大量的缓存层,访问缓存中的内存的成本可能比访问不在缓存中的内存的成本快数百倍或数千倍。在d元堆中增加d值时,树中的层更少,访问的元素更接近,从而提供更好的局部性。找到最佳点可能需要一些实验,如果d=4恰好是您机器上最好的,那么就去尝试吧

EDIT:正如@moreON所指出的,对于d=4,堆中的层数减少了两倍,而每次比较的数量增加了两倍,这实际上可能会由于缓存效应和较低的总体树高而提供更好的总体性能。因此,它可能是优于二进制堆的一个很好的候选者


希望这有帮助

理论上,四元堆比二进制堆快


由于三元堆在a中的开销很大,且f(k=4)对于去队列操作,也有一些更好的局部参考,对于较大的D,因为你有更多的子节点,它们都是在内存中顺序考虑的。因为这一点和你所说的,它可以双向实现。对于2对4(而不是10^100)来说,同样至关重要的是,4进制的级别大约是2进制的一半,每个节点的子节点数量是2进制的两倍,用于基本相同数量的比较,但在一个大堆中,引用的整体局部性更好,如上所述。@moreON我没有想到使用多个排队操作的大型d的局部性好处。谢谢分享!Dijkstra算法使用的减少优先级操作比删除最小优先级操作更多。(假设边多于顶点。)