Fibonacci堆:插入,提取 - 最小和性能?

时间:2013-01-11 02:47:26

标签: algorithm data-structures heap dijkstra fibonacci-heap

我试图了解斐波纳契堆,在堆中插入元素的伪代码是:

Fibonacci-Heap-Insert(H,x)
degree[x] := 0
p[x] := NIL
child[x] := NIL
left[x] := x
right[x] := x
mark[x] := FALSE
concatenate the root list containing x with root list H
if min[H] = NIL or key[x]<key[min[H]]
      then min[H] := x
n[H]:= n[H]+1

以下是一些我不理解的事情,

  • 什么是root list containing x以及如何将其与包含H?
  • 的根列表连接起来

在提取min时,我们做了类似的事情:

    Fibonacci-Heap-Extract-Min(H)
     z:= min[H]
     if x <> NIL
         then for each child x of z
            do add x to the root list of H
                p[x]:= NIL
            remove z from the root list of H
            if z = right[z]
                then min[H]:=NIL
            else
                  min[H]:=right[z]
                  CONSOLIDATE(H)
            n[H] := n[H]-1
     return z

(以下是其他功能,合并和链接,http://www.cse.yorku.ca/~aaw/Jason/FibonacciHeapAlgorithm.html

  • 在上一个插入函数中,我们设置child,并将x设为nil,while提取min,if <> nil将始终为false,因此如果我们调用它,它将永远不会给出准确的min功能多次。

  • 如果这个结构被称为斐波那契'堆',它在哪里维护堆属性?

  • 如果我们在Dijkstra的算法中使用二进制堆而不是斐波那契堆,那么所用的时间几乎和我们使用数组或链表一样慢吗?

有谁可以解释我遇到的困难? 谢谢。

1 个答案:

答案 0 :(得分:2)

这里有很多问题,所以我会尽力回答所有这些问题。

对于您的第一个问题:Fibonacci堆实现为一组树,它们全部链接在一起,形成一个循环的双向链表。当插入函数要求您将x与根列表H连接时,它要求您获取您创建的单个节点(x)并将其连接到所有现有树H的循环双向链表中。< / p>

关于extract-min的问题,您的伪代码中存在错误。测试

x <> NIL

应该是

z <> NIL

x在函数中没有定义,因此这段代码无法按写入方式工作。

关于如何维护堆属性:Fibonacci堆中的每个树都单独服从堆属性。调用CONSOLIDATE时,可以将多个树合并回单个树中。这是堆属性的维护位置。将两个树合并在一起时,Fibonacci堆始终使用具有较大根值的树并使其成为树的根的子节点,其根的值较小。这样,生成的树就会遵循堆属性。

最后,Dijkstra和堆:Dijkstra的算法与基于堆的优先级队列需要时间O(m log n)才能完成,而Fibonacci堆支持的Dijkstra需要O(m + n log n),这是渐近更快对于稀疏图。然而,在实践中,斐波那契堆通常比二进制堆更慢,因为大O项中隐藏了更高的常数因子,这都是因为实现更加复杂并且因为它们具有更差的参考局部性。然而,Dijkstra的二进制堆版本在理论上和实践上都比Dijkstra的链表或排序阵列支持版本快得多。

希望这有帮助!