你们中有没有人实施过斐波那契堆?几年前,我这样做了,但是比使用基于数组的BinHeaps要慢几个数量级。
那时,我认为这是一门宝贵的课程,说明研究并不总是像它声称的那样好。但是,许多研究论文声称其算法基于使用斐波那契堆的运行时间。
您是否曾经设法产生有效的实施方案?还是您使用的数据集如此之大,以至于斐波那契堆更有效?如果是这样,一些细节将不胜感激。
你们中有没有人实施过斐波那契堆?几年前,我这样做了,但是比使用基于数组的BinHeaps要慢几个数量级。
那时,我认为这是一门宝贵的课程,说明研究并不总是像它声称的那样好。但是,许多研究论文声称其算法基于使用斐波那契堆的运行时间。
您是否曾经设法产生有效的实施方案?还是您使用的数据集如此之大,以至于斐波那契堆更有效?如果是这样,一些细节将不胜感激。
Answers:
所述升压C ++库包括斐波那契堆在一个实现boost/pending/fibonacci_heap.hpp
。该文件显然已经存在pending/
多年,根据我的预测,该文件将永远不会被接受。另外,该实现中也存在一些错误,这些错误是由我和熟人Aaron Windsor所熟识的。不幸的是,我可以在网上找到的那个文件的大多数版本(以及Ubuntu的libboost-dev软件包中的那个)仍然存在bug。我不得不从Subversion存储库中提取一个干净的版本。
从1.49 版开始,Boost C ++库添加了许多新的堆结构,包括斐波那契堆。
我能够编译dijkstra_heap_performance.cpp对修改后的版本dijkstra_shortest_paths.hpp比较斐波那契堆和二进制堆。(在一行中typedef relaxed_heap<Vertex, IndirectCmp, IndexMap> MutableQueue
,更改relaxed
为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堆,您必须在reduce_keys非常频繁的应用程序中使用它们。用Dijkstra来说,这意味着基础图是密集的。某些应用程序可能本质上是reduce_key-intense; 我想尝试Nagomochi-Ibaraki最小删节算法,因为它显然会生成很多reduce_keys,但是要使时序比较正常工作需要付出很大的努力。
警告:我可能做错了什么。您不妨尝试自己重现这些结果。
理论注释:Fibonacci堆在reduce_key上的性能提高对于理论应用程序(例如Dijkstra的运行时)很重要。Fibonacci堆在插入和合并时也胜过二进制堆(Fibonacci堆的均摊固定时间)。插入本质上是无关紧要的,因为它不会影响Dijkstra的运行时,并且修改二进制堆以在固定的固定时间内插入也相当容易。固定时间合并非常好,但与该应用程序无关。
个人说明:我的一个朋友和我曾经写过一篇论文,解释了一个新的优先级队列,该队列试图在没有复杂性的情况下复制Fibonacci堆的(理论上)运行时间。该论文从未发表过,但是我的合著者确实实现了二进制堆,斐波那契堆以及我们自己的优先级队列来比较数据结构。实验结果的图表表明,就总比较而言,斐波那契堆的性能稍好于二进制堆,这表明在比较成本超过开销的情况下,斐波那契堆的性能会更好。不幸的是,我没有可用的代码,大概在您的情况下比较便宜,因此这些注释是相关的,但不直接适用。
顺便提一句,我强烈建议尝试将Fibonacci堆的运行时与您自己的数据结构进行匹配。我发现自己只是重新发明了斐波那契堆。在我以为斐波那契堆的所有复杂性都是一些随机的想法之前,但后来我意识到它们都是自然的并且相当强迫。
克努斯(1993年)在他的书“ 斯坦福Graphbase”中对斐波那契堆和二进制堆进行了最小生成树的比较。他发现在测试的图形尺寸下,斐波那契比二进制堆慢30%至60%,在不同密度下有128个顶点。
的源代码是在C(或者更确切地说CWEB其是C,数学和TeX的之间的交叉)的部分MILES_SPAN。
免责声明
我知道结果非常相似,并且“看起来运行时间完全由堆以外的其他东西控制”(@Alpedar)。但是我在代码中找不到任何证据。它的代码是开放的,因此,如果您发现任何可能影响测试结果的内容,请告诉我。
也许我做错了什么,但是我基于A.Rex anwser比较编写了一个测试:
所有堆的执行时间(仅适用于完整图形)非常接近。对具有1000、2000、3000、4000、5000、6000、7000和8000个顶点的完整图形进行了测试。对于每个测试,生成了50个随机图,并且输出是每个堆的平均时间:
抱歉,输出不是很冗长,因为我需要它从文本文件中构建一些图表。
结果如下(以秒为单位):
我还对斐波那契堆做了一个小实验。这是详细信息的链接:Experimenting-dijkstras-algorithm。我只是用谷歌搜索“斐波那契堆java”一词,并尝试了一些斐波那契堆的现有开源实现。似乎其中一些存在性能问题,但是有些还不错。至少,在我的测试中,它们击败了天真和二进制堆PQ性能。也许他们可以帮助实现高效的解决方案。