有没有人真正有效地实施了斐波纳契堆?

时间:2009-02-02 20:46:38

标签: performance algorithm language-agnostic data-structures fibonacci-heap

你们有没有人实施Fibonacci-Heap?几年前我这样做了,但它比使用基于阵列的BinHeaps慢几个数量级。

那时候,我认为这是一个宝贵的教训,研究的结果并不像它声称的那样好。然而,许多研究论文声称他们的算法的运行时间基于使用Fibonacci-Heap。

你有没有设法产生有效的实施?或者您使用的数据集如此之大,以至于Fibonacci-Heap效率更高?如果是这样,一些细节将不胜感激。

4 个答案:

答案 0 :(得分:131)

Boost C++ libraries包含boost/pending/fibonacci_heap.hpp中斐波那契堆的实现。这个文件显然已经在pending/多年了,我的预测永远不会被接受。此外,该实现中存在一些错误,这些错误由我的熟人和全能酷男Aaron Windsor修复。不幸的是,我在网上找到的那个文件的大多数版本(以及Ubuntu的libboost-dev软件包中的那个版本)仍然存在错误;我不得不从Subversion存储库中提取a clean version

由于版本1.49 Boost C++ libraries添加了许多新的堆结构,包括斐波纳契堆。

我能够针对dijkstra_heap_performance.cpp的修改版本编译dijkstra_shortest_paths.hpp,以比较Fibonacci堆和二进制堆。 (在typedef relaxed_heap<Vertex, IndirectCmp, IndexMap> MutableQueue行中,将relaxed更改为fibonacci。)我首先忘记了使用优化进行编译,在这种情况下,Fibonacci和二进制堆的执行大致相同,Fibonacci堆通常优于微不足道的数额。经过非常强大的优化编译后,二进制堆得到了巨大的推动。在我的测试中,当图形非常大且密集时,Fibonacci堆只有超过二进制堆,例如:

Generating graph...10000 vertices, 20000000 edges.
Running Dijkstra's with binary heap...1.46 seconds.
Running Dijkstra's with Fibonacci heap...1.31 seconds.
Speedup = 1.1145.

据我所知,这触及了Fibonacci堆和二进制堆之间的根本区别。两个数据结构之间唯一真正的理论差异是Fibonacci堆支持(摊销)恒定时间中的减少键。另一方面,二进制堆从它们作为数组的实现中获得了很大的性能;使用显式指针结构意味着斐波纳契堆受到巨大的性能损失。

因此,要从实践中的斐波那契堆中受益,您必须在reduce_keys非常频繁的应用程序中使用它们。就Dijkstra而言,这意味着底层图是密集的。一些应用程序可能本质上是reduce_key-intense;我想尝试the Nagomochi-Ibaraki minimum-cut algorithm,因为它显然会产生很多的reduce_keys,但是要让时序比较工作太费劲了。

警告:我可能做错了什么。您可能希望尝试自己复制这些结果。

理论注释:对于理论应用,例如Dijkstra的运行时,Fibonacci堆在decrease_key上的改进性能非常重要。 Fibonacci堆在插入和合并时也优于二进制堆(对于Fibonacci堆都是平均化的常数时间)。插入本质上是不相关的,因为它不会影响Dijkstra的运行时,并且修改二进制堆也很容易插入到分摊的常量时间。在恒定时间内合并非常棒,但与此应用程序无关。

个人笔记:我的一位朋友和我曾写过一篇论文,解释了一个新的优先级队列,它试图复制斐波那契堆的(理论上)运行时间而没有它们的复杂性。该论文从未发表过,但我的合着者确实实现了二进制堆,Fibonacci堆和我们自己的优先级队列来比较数据结构。实验结果的图表表明斐波那契在总比较方面略微超出了二进制堆,这表明斐波那契堆在比较成本超过开销的情况下表现更好。不幸的是,我没有可用的代码,并且可能在你的情况下比较便宜,所以这些评论是相关的,但不能直接适用。

顺便说一句,我强烈建议尝试将Fibonacci堆的运行时与您自己的数据结构相匹配。我发现我自己彻底改造了斐波那契堆。在我认为Fibonacci堆的所有复杂性是一些随机的想法之前,但后来我意识到它们都是自然而且相当强迫。

答案 1 :(得分:32)

Knuth在1993年为他的书Stanford Graphbase做了最小生成树的斐波纳契堆和二元堆之间的比较。他发现斐波那契在他测试的图形尺寸上比二进制堆慢30到60%,在不同密度下有128个顶点。

source code在MILES_SPAN部分的C中(或者更确切地说是CWEB,它是C,math和TeX之间的交叉)。

答案 2 :(得分:1)

<强>声明

我知道结果非常相似,“看起来运行时间完全由堆以外的其他东西支配”(@Alpedar)。但我在代码中找不到任何证据。 它是打开的代码,所以如果你能找到任何可能影响测试结果的东西,请告诉我。


也许我做错了什么,但我wrote a test,基于A.Rex anwser比较:

  • 斐波-堆
  • D-Ary-heap(4)
  • 二进制堆
  • 宽松堆

所有堆的执行时间(仅适用于完整图表)非常接近。 对具有1000,2000,3000,4000,5000,6000,7000和8000个顶点的完整图形进行了测试。对于每个测试,生成50个随机图,输出是每个堆的平均时间:

对输出感到抱歉,它不是很冗长,因为我需要它从文本文件构建一些图表。


以下是结果(以秒为单位):

heap result table

答案 3 :(得分:0)

我还做了一个Fibonacci堆的小实验。以下是详细信息的链接:Experimenting-with-dijkstras-algorithm。我只是搜索了“Fibonacci heap java”这个术语,并尝试了一些现有的Fibonacci堆的开源实现。似乎其中一些有一些性能问题,但有一些是非常好的。至少,他们在我的测试中击败了天真和二进制堆PQ性能。也许他们可以帮助实现有效的。