我试图了解斐波纳契堆,在堆中插入元素的伪代码是:
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的算法中使用二进制堆而不是斐波那契堆,那么所用的时间几乎和我们使用数组或链表一样慢吗?
有谁可以解释我遇到的困难? 谢谢。
答案 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的链表或排序阵列支持版本快得多。
希望这有帮助!