如何使用Fibonacci堆实现Prim的算法?

时间:2011-01-28 06:30:16

标签: algorithm data-structures graph-algorithm prims-algorithm fibonacci-heap

我知道Prim's algorithm并且我知道它的实现,但我总是跳过我想要问的部分。有人写道,Prim的Fibonacci heap算法实现是O(E + V log(V))我的问题是:

  • 简言之,什么是斐波纳契堆?
  • 如何实施?和
  • 如何使用Fibonacci堆实现Prim的算法?

3 个答案:

答案 0 :(得分:28)

Fibonacci堆是一个相当复杂的优先级队列,在其所有操作中具有出色的amoritzed渐近行为 - inserted,find-min和reduce-key都在O(1)摊销时间运行,而delete和extract-min运行在摊销的O(lg n)时间内。如果您想要对该主题有一个很好的参考,我强烈建议您阅读CLRS的“算法简介,第2版”并阅读其中的章节。它写得非常好,非常具有说明性。 The original paper on Fibonacci heaps by Fredman and Tarjan可在线获取,您可能需要查看。它很密集,但对材料进行了很好的处理。

如果你想看到Fibonacci堆和Prim算法的实现,我必须为我自己的实现提供一个无耻的插件:

  1. My implementation of a Fibonacci heap.
  2. My implementation of Prim's algorithm using a Fibonacci heap.
  3. 这两个实现中的注释应该提供关于它们如何工作的非常好的描述;让我知道我能做些什么来澄清!

答案 1 :(得分:12)

Prim算法选择已经选择的涡旋组与其余涡旋之间权重最低的边。
因此,要实现Prim算法,您需要一个最小堆。每次选择边缘时,都会将新涡旋添加到已经选择的涡旋组中,并且所有相邻边缘都会进入堆中。
然后从堆中再次选择具有最小值的边。

所以我们得到的时间是:
斐波那契:
选择最小边= O(移除最小值的时间)= O(log(E))= O(log(V))
将边插入堆= O(将项插入堆的时间)= 1

最小堆:
选择最小边= O(从堆中移除最小值的时间)= O(log(E))= O(log(V))
将边插入堆= O(将项插入堆的时间)= O(log(E))= O(log(V))

(请记住,E = ~V ^ 2 ...所以log(E)== log(V ^ 2)== 2Log(V)= O(log(V))

所以,总共有E插入和V最小选择(最后是树)。

所以在Min heap中你会得到:

O(Vlog(V)+ Elog(V))== O(Elog(V))

在Fibonacci堆中你会得到:

O(Vlog(V)+ E)

答案 2 :(得分:2)

几年前,我使用Fibonacci堆实现了Dijkstra,问题非常相似。基本上,Fibonacci堆的优点在于它可以找到一组常量运算的最小值;所以这对Prim和Dijkstra来说非常合适,你必须在每一步都执行这项操作。

为什么好呢

使用二项式堆(这是更“标准”的方式)的那些算法的复杂性是O(E * log V),因为 - 粗略地 - 你将尝试每个边缘(E),并且对于它们中的每一个你将新的顶点添加到二项式堆(日志V)或减少其键(日志V),然后必须找到堆的最小值(另一个日志V)。

相反,当您使用Fibonacci堆时,在堆中插入顶点或减少其键的成本是不变的,因此您只有O(E)。但是删除一个顶点是O(log V),因此最后将删除每个顶点,为总O(E + V * log V)添加O(V * log V)。

因此,如果您的图表足够密集(例如E>> V),则使用Fibonacci堆比二项式堆更好。

如何

因此,我们的想法是使用Fibonacci堆来存储可从您构建的子树中访问的所有顶点,并通过导致它的最小边的权重进行索引。如果您使用其他数据结构了解实现或Prim的算法,那么使用Fibonacci堆就没有真正的困难 - 只需使用堆的 insert deletemin 方法正如您通常所做的那样,当释放通向它的边时,使用减小键方法更新顶点。

唯一困难的部分是实现实际的Fibonacci堆。

我不能在这里给你所有的实施细节(这会占用页面),但是当我做了我的时候,我非常依赖Introduction to algorithms (Cormen et al)。如果您还没有,但对算法感兴趣,我强烈建议您获得它的副本!它与语言无关,它提供了有关所有标准算法及其证明的详细解释,并且肯定会提高您的知识和使用所有标准的能力,并设计和证明新的标准。 This PDF(来自您链接的Wikipedia页面)提供了一些实现细节,但它绝对不如算法简介那么清晰。

我有一个report和一个presentation我写完之后,这解释了一些如何继续(对于Dijkstra - 请参阅伪代码中的Fibonacci堆函数的ppt的结尾)但它全部是法语...我的code是Caml(和法语)所以我不确定这是否有帮助!如果你能理解它的某些内容请放纵,我只是开始编程,所以当时我的编码技巧很差......