Fibonacci Heaps

motivation

A Fibonacci heap can be viewed as an extension of Binomial heaps which supports DECREASE-KEY and DELETE operations efficiently.

我们为什么需要更高效的 decreaseKey?

设想在 Dijkstra单源点最短路径问题上,G=(V,E), |V| = n, |E| = m,我们使用优先队列,算法实现可看为 n 次 insert,n 次 extractMin 和 m 次decreaseKey 的 sequnce. 用 amortized cost = O ( n ⋅ T i n s e r t + n ⋅ T e x t r a c t M i n + m ⋅ T d e c r e a s e K e y ) O(n\cdot T_{insert} + n\cdot T_{extractMin} +m\cdot T_{decreaseKey}) O(nTinsert+nTextractMin+mTdecreaseKey). 我们知道无论如何优化 n 次 insert 和n 次 extractMin 是无法优于 O ( n log ⁡ n ) O(n\log n) O(nlogn)的。那么就只能考虑在其他不变的情况下,优化 decreaseKey.

Fibonacci Heaps

已知 binary 和 binomial heaps 的 decreaseKey 都取决于树的高度,O(log n). 对于斐波那契堆我们希望把decreaseKey的复杂度降到O(1) —— decreaseKey 直接将该 node 从它的 parent 取下来,再加入到 set 里,其余操作均与 lazy binomial heap相同,详见lazy binomial heap.

decreaseKey

但是这样会有一些问题,因为我们无法同时保持下面三种性质:

  • decrease-key takes time O(1).
  • Our trees are heap-ordered.
  • Our trees are binomial tree.

那就放弃第三条好了,这样可以随心所欲地 cut (decreaseKey).

extractMin 变慢了?

但是这样仍然会有一些问题,插入依然是 lazy meld,但如何去extractMin 呢?像之前的情况,case (a),参照 lazy binomial heap extractMin 时 coalesce step 的方式去合并。
case a

distribute order

但现在 set 里面的 tree 不再是 binomial tree了,每一棵树 nodes 个数不再是 2 k 2^k 2k,order 如何再去标记?类似下面这种情况,case (b),怎么合并?

case b

一种解决办法是令一棵树的 order 等于 其 root 的 rank,即 root 有几个孩子。然后同 coalesce step 中按 order 分配再从低到高合并。
distribute order
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Mwe5QXG-1592380015145)(https://upload-images.jianshu.io/upload_images/23517192-dfaddb3f929caf8e.gif?imageMogr2/auto-orient/strip)]

**但是其实这样的做法会出现很严重的问题。就是我们的树的形状不再 well-constrained. Nodes 个数 不再与这棵树的 order 成 exponential 关系。**heap 里可能会出现这样形状的树:
bad-constrained
例

因为我们知道在对于 lazy binomial heap 的 extractMin 时进行 均摊复杂度分析时, O ( log ⁡ n ) O(\log n) O(logn)是依赖于最终合并后 binomial tree n 个 nodes 最多有 O ( log ⁡ n ) O(\log n) O(logn)棵树的。而此时,树的个数变成了 O ( n 1 2 ) O(n^{\frac{1} {2}}) O(n21). 这就很让人头大… O ( 1 ) O(1) O(1)的decreaseKey 是牺牲了 extractMin, O ( n 1 2 ) O(n^{\frac{1} {2}}) O(n21)为代价的。

Solution

解决的思路是增加限制重新使 nodes exponential 于 tree 的 rank.

Solution: Limit #cuts among the children of any node to 2.

依然用 root 的孩子数作为 rank,但同时限制任何一个 node 最多只能失去 一个孩子。当其失去第二个孩子时,它也同时被从它的父节点取下来,从而可能造成一连串的级联切割——cascading cut. 实现时,所有节点初始均未标记。当一节点失去一个孩子时,将其标记。当其失去第二个孩子时,同时将该节点取下,并解除其标记加回到 set 里。

下面用两种方法证明这种方法构造的树 nodes exponential 于 tree 的 rank.

数理证明

整体思路是证明上面 solution 所构造 order 为 k 的 tree,所包含的节点数为斐波那契数 f k + 2 f_{k+2} fk+2.
首先回顾 Fibonacci 数列:
f n = { 0 n = 0 , 1 n = 1 , f n − 1 + f n − 2 n ≥ 2. f_n=\begin{cases} 0& n=0,\\ 1 & n=1,\\ f_{n-1}+f_{n-2} & n\geq2. \end{cases} fn=01fn1+fn2n=0,n=1,n2.

其特征方程 z 2 − z − 1 = 0 z^2-z-1 = 0 z2z1=0 有两特征根 ϕ = 1 + 5 2 \phi = \frac{1+\sqrt{5}} {2} ϕ=21+5 ϕ ^ = 1 − 5 2 \hat{\phi} = \frac{1-\sqrt{5}} {2} ϕ^=215 . 通项公式 f n = 1 5 ( ϕ n + ϕ ^ n ) f_n = \frac{1}{\sqrt{5}}(\phi^n+\hat{\phi}^n) fn=5 1(ϕn+ϕ^n)

Lemma 1. For all integers $ n \geq0$, f n + 2 = 1 + ∑ i = 0 n f i f_{n+2} = 1+ \sum_{i=0}^{n}{f_i} fn+2=1+i=0nfi
Proof by induction on n n n.
Base case. n = 0 n = 0 n=0, f 2 = f 1 + f 0 = 1 f_2 = f_1+f_0 = 1 f2=f1+f0=1 成立。
Induction Hypothesis: f k + 2 = 1 + ∑ i = 0 k f i f_{k+2} = 1+\sum_{i=0}^k{f_i} fk+2=1+i=0kfi for 0 ≤ k ≤ n − 1 0\leq k\leq n-1 0kn1
To prove it holds for k = n k = n k=n.
f n + 2 = f n + 1 + f n = 1 + ∑ i = 0 n − 1 f i + f n = 1 + ∑ i = 0 n f i f_{n+2} = f_{n+1}+f_{n} =1+\sum_{i=0}^{n-1}{f_i} + f_n=1+\sum_{i=0}^{n}{f_i} fn+2=fn+1+fn=1+i=0n1fi+fn=1+i=0nfi, 成立。

然后是尝试建立指数关系。
Lemma 2. For all integers $ n \geq0$, f n + 2 ≥ ϕ n f_{n+2}\geq \phi^n fn+2ϕn
Proof by induction on n n n.
Base case. f 2 = 1 = ϕ 0 f_2 = 1 = \phi^0 f2=1=ϕ0, f 3 = 2 ≥ ϕ 1 f_3 = 2 \geq \phi^1 f3=2ϕ1
Induction Hypothesis: f k + 2 ≥ ϕ k f_{k+2} \geq \phi^k fk+2ϕk for 0 ≤ k ≤ n − 1 0\leq k\leq n-1 0kn1
To prove it holds for k = n k = n k=n.
f n + 2 = f n + 1 + f n ≥ ϕ n − 1 + ϕ n − 2 = ( ϕ + 1 ) ⋅ ϕ n − 2 = ϕ 2 ⋅ ϕ n − 2 = ϕ n f_{n+2} = f_{n+1}+f_{n} \geq \phi^{n-1}+\phi^{n-2} = (\phi+1)\cdot \phi^{n-2} = \phi^2\cdot \phi^{n-2} = \phi^n fn+2=fn+1+fnϕn1+ϕn2=(ϕ+1)ϕn2=ϕ2ϕn2=ϕn, 成立。

然后是任何一个树内 node 的 rank 的限制。
Lemma 3. :Let x x x be any node in a Fibonacci heap, and suppose that $ k = rank(x)$. Let y 1 , y 2 , . . . , y k y_1, y_2,..., y_k y1,y2,...,yk be the children of x x x in the order in which they were linked to x x x, from the earliest to the latest. Then r a n k ( y i ) ≥ max ⁡ ( 0 , i − 2 ) rank(y_i) \geq \max(0,i-2) rank(yi)max(0,i2).
Lemma 3

Proof. 显然 r a n k ( y 1 ) = 0 rank(y_1)=0 rank(y1)=0 成立。
对于 i > 1 i>1 i>1的情况,当 y i y_i yi 被 linked 到 x x x时(与 x x x合并), y 1 , y 2 , . . . , y i − 1 y_1, y_2,..., y_{i-1} y1,y2,...,yi1已经 linked 到 x x x了,所以此时 r a n k ( x ) = i − 1 rank(x) = i-1 rank(x)=i1。那么因为只有对于同秩的 tree 才会合并,所以此时 r a n k ( y i ) = r a n k ( x ) = i − 1 rank(y_i) = rank(x) = i-1 rank(yi)=rank(x)=i1.
因为此后 y i y_i yi仍属于 x x x的孩子,所以其最多损失一个孩子, r a n k ( y i ) ≥ i − 2 rank(y_i)\geq i-2 rank(yi)i2, 证毕。

最后用前面的引理1, 2 和 3结合来证明 rank 与 节点数的关系。
Lemma 4. Let z z z be any node in a Fibonacci heap with n = s i z e ( z ) n = size(z) n=size(z) and r = r a n k ( z ) r = rank(z) r=rank(z). Then r = log ⁡ ϕ n r = \log_\phi n r=logϕn.
Proof.
假设 S k S_k Sk是斐波那契堆里任意 rank 为 k k k的节点,以其为根的树所包含的节点个数(size).
显然 S 0 = 1 , S 1 = 2 S_0 = 1, S_1 = 2 S0=1,S1=2. 它们都不能失去任何孩子。
且对二者增加孩子,以构成 S 2 , S 3 . . . S_2, S_3... S2,S3...只会使 nodes 个数增加,size 随 order 增加不会减少。
x x x是斐波那契堆里任意一点,其秩 r = r a n k ( x ) r = rank(x) r=rank(x), 节点个数 S r = s i z e ( x ) S_r = size(x) Sr=size(x)

使用Lemma 3的假设和结论。令 x x x的孩子,按被 linked 的顺序为 y 1 , y 2 , . . . , y k y_1, y_2,..., y_k y1,y2,...,yk.
那么就有 S r ≥ 1 + ∑ i = 1 r S r a n k ( y i ) ≥ 1 + ∑ i = 1 r S max ⁡ ( 0 , i − 2 ) = 2 + ∑ i = 2 r S i − 2 S_r \geq 1+\sum_{i=1}^rS_{rank(y_i)} \geq 1+\sum_{i=1}^rS_{\max(0,i-2)} = 2 + \sum_{i=2}^rS_{i-2} Sr1+i=1rSrank(yi)1+i=1rSmax(0,i2)=2+i=2rSi2

接下来证明 S r ≥ f r + 2 S_r \geq f_{r+2} Srfr+2,对于所有 r ≥ 0 r\geq 0 r0。即 rank = r 的 tree 的 size, S r S_r Sr 大于等于斐波那契数, f r + 2 f_{r+2} fr+2。然后依据Lemma 2,由于 f r + 2 ≥ ϕ r f_{r+2}\geq \phi^r fr+2ϕr,所以 size 和 order(rank) 呈指数关系。

Proof by induction on n n n.
Base case. S 0 = 1 = f 2 S_0 = 1 = f_2 S0=1=f2, S 1 = 2 = f 3 S_1 = 2 = f_3 S1=2=f3,成立。
Induction Hypothesis. It holds for 0 ≤ k ≤ r − 1 0\leq k \leq r-1 0kr1 that S k ≥ f k + 2 S_k \geq f_{k+2} Skfk+2.
To prove it holds for k = r k = r k=r. 使用 S r ≥ 2 + ∑ i = 2 r S i − 2 S_r \geq 2 + \sum_{i=2}^rS_{i-2} Sr2+i=2rSi2就可以用 Induction Hypothesis 了。
S r ≥ 2 + ∑ i = 2 r S i − 2 ≥ 2 + ∑ i = 2 r f i = 1 + ∑ i = 1 r f i = f r + 2 S_r \geq 2+\sum_{i=2}^rS_{i-2} \geq 2+\sum_{i=2}^rf_i = 1+\sum_{i=1}^rf_i = f_{r+2} Sr2+i=2rSi22+i=2rfi=1+i=1rfi=fr+2.

由此,我们推出了 n ≥ S r ≥ f r + 2 ≥ ϕ r n \geq S_r \geq f_{r+2} \geq \phi^r nSrfr+2ϕr    ⟹    r = log ⁡ ϕ n \implies r = \log_\phi n r=logϕn,nodes exponential 于 rank。

Maximally-Damaged Trees

上面那是石溪教材上的数理证明,下面是大S给出的更直观的证明。

Maximally-Damaged Trees

就是说我们对于一个 full 的 rank = k 的 binomial tree 去尝试截掉它所有不影响其 rank 的节点。这样就得到了斐波那契堆里 rank 为 k 的树的最少节点数——此时 tree 是 maximally damaged.

然后我们通过观察发现,这这些 minimum number 是 斐波那契数列—— order + 1 的 maximally damaged tree 就是 order - 2 的 tree 被 linked 到 order -1 的 tree上。而由数理归纳可知斐波那契数的增长是指数级的,所以 ↓ \downarrow

claim: The minimum number of nodes in a tree of order k k k is F k + 2 F_{k+2} Fk+2. 殊途同归。

Proof by induction on rank.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gBo0elkT-1592380015150)(https://upload-images.jianshu.io/upload_images/23517192-099ea0483b94eb70.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
Induction Hypothesis. for 0 ≤ k ≤ n 0\leq k \leq n 0kn, order 为 k k k的树最少含有节点 F k + 2 . F_{k+2}. Fk+2.

To prove it holds for k = n k=n k=n.
order = k k k 的树的孩子的 order 为 0 , 0 , 1 , . . . , k − 2 0,0,1,...,k-2 0,0,1,...,k2,这是由 maximally damaged trees 而来性质而来,它合并了 order = k − 1 k-1 k1 k − 2 k-2 k2 的maximally damaged tree.
而 order = k + 1 k+1 k+1 的树,则由 order = k k k k − 1 k-1 k1 合并,如图。

根据 IH, order = k − 1 k-1 k1 的树节点数 ≥ F k + 1 \geq F_{k+1} Fk+1, order = k k k树节点数 ≥ F k + 2 \geq F_{k+2} Fk+2,则二者合并 order = k + 1 k+1 k+1 的树节点数 = F k + 1 + F k + 2 = F k + 3 =F_{k+1}+F_{k+2} = F_{k+3} =Fk+1+Fk+2=Fk+3, it holds for k + 1 k+1 k+1.

induction step

Amortized analysis

decreaseKey

**首先是 decreaseKey 的复杂度。**尽管我们希望能把它优化到 O ( 1 ) O(1) O(1),可以自从限制了 cut 次数以后,就可能出现级联 cut 的情况。如图:
cascading cut

这样worst-case 的复杂度就变成了 O ( log ⁡ n ) O(\log n) O(logn),一串 cut 取决于树高。 下面使用 potential method 来看一下 decreaseKey 的均摊复杂度。

先观察,对于 k k k次级联 cut 的 decreaseKey 会使 tree 的个数增加 k k k,不能再令 Φ = \Phi = Φ= # of trees。而在 trees 增加的同时,每一次级联 cut 都会还原一个 marked node。不妨令 Φ = t + 2 m \Phi = t + 2m Φ=t+2m, t t t是 trees 的个数, m m m是 marked nodes 的个数。

这里之所以采用 t + 2 m t+2m t+2m,是考虑 t + m t+m t+m的话,减少的 mark nodes 知识 刚刚好抵消掉 tree的增加,而还要对 actual cost 进行抵消,所以考虑用 Φ = t + 2 m \Phi = t+2m Φ=t+2m.

假设某次 decreaseKey 开始前,# of mark nodes = m m m,# of trees = t t t. Φ b e f o r e = t + 2 m \Phi_{before} = t+2m Φbefore=t+2m
操作进行了 k k k次级联 cut。actual cost = 1 + k 1+k 1+k
新增 trees 1 + k 1+k 1+k, mark nodes 1 − k 1-k 1k. 因为 k k k次级联 cut 后,必新增 1 mark node.
Δ Φ = 3 − k \Delta \Phi = 3-k ΔΦ=3k, T a m o r t i z e d ( d e c r e a s e K e y ) = 1 + k + C ⋅ ( 3 − k ) = O ( 1 ) T_{amortized}(decreaseKey) = 1+k + C\cdot (3-k) = O(1) Tamortized(decreaseKey)=1+k+C(3k)=O(1)

由此可知我们确实把 decreaseKey 的均摊复杂度降到了 O ( 1 ) . O(1). O(1). 期待 Dijkstra的更好性能吧!

extractMin

**extractMin的复杂度。**只分析均摊复杂度就够了,worst-case 如 lazy binomial heap。

extractMin 之前,# of mark nodes = m m m,# of trees = t t t. Φ b e f o r e = t + 2 m \Phi_{before} = t+2m Φbefore=t+2m

  • 通过***min***指针找到 min, remove min 新增 trees O ( log ⁡ n ) O(\log n) O(logn),再 add back 的 actual cost O ( log ⁡ n ) O(\log n) O(logn)
  • coalesce step: trees 变为 O ( log ⁡ n ) O(\log n) O(logn), actual cost = O ( t + log ⁡ n ) O(t+\log n) O(t+logn)
    • 先创建 order box, actual cost = O ( log ⁡ n ) O(\log n) O(logn)
    • 再按 order 分配并合并。trees 变为 O ( log ⁡ n ) O(\log n) O(logn), actual cost = O ( t ) O(t) O(t)
  • update min 指针, O ( log ⁡ n ) O(\log n) O(logn).

自始至终 mark nodes 个数都不会改变。
Δ Φ = − t + log ⁡ n \Delta \Phi = -t + \log n ΔΦ=t+logn, actual cost = O ( t + log ⁡ n ) O(t+\log n) O(t+logn), T a m o r t i z e d ( e x t r a c t M i n ) = − t + log ⁡ n + O ( t + log ⁡ n ) = O ( log ⁡ n ) T_{amortized}(extractMin) = -t + \log n + O(t+\log n) = O(\log n) Tamortized(extractMin)=t+logn+O(t+logn)=O(logn)
分析跟 lazy binomial heap 的 extractMin 完全一致(依赖于 exponential 关系)。

delete

**delete 的复杂度。**前面说斐波那契堆支持更高效的 decreaseKey 和 delete,delete的复杂度?

d e l e t e ( H , x ) delete(H,x) delete(H,x) 可以看作是 首先 d e c r e a s e K e y ( H , x , − ∞ ) decreaseKey(H,x,-\infty) decreaseKey(H,x,), 再去 e x t r a c t M i n ( H ) extractMin(H) extractMin(H).
所以其均摊复杂度, T a m o r t i z e d ( d e l e t e ) = O ( 1 ) + O ( log ⁡ n ) = O ( log ⁡ n ) T_{amortized}(delete) = O(1)+O(\log n) = O(\log n) Tamortized(delete)=O(1)+O(logn)=O(logn)

其实没什么提升,lazy binomial heap 中 delete 也是 O ( log ⁡ n ) O(\log n) O(logn) 的均摊复杂度。

where are we now

performance

拿到了这样的“神器”,Fibonacci heap 实现的优先队列来解决单源点最短路径问题能否起飞呢?

representation problem

回顾开局那张 decreaseKey 的图,其实细节上有些错误。因为要把 一个节点从其父节点的link中取下来,必然得找到父节点。那 parent 和 child 之间就必须得是双向的 link。如图:
representation

但是这样仍会有问题。试想上图中 decrease D 的 key。

  • 拿到 D 就找到了 A。找到 A 后,就先抹掉 D 指向 A 的 link, O ( 1 ) O(1) O(1).
  • 剩下只需要把 A 指向 D 的 link 删掉,D 就彻底被移除了,然而找到 A-D link O ( log ⁡ n ) . O(\log n). O(logn).

这就很尴尬,因为我们想要 O ( 1 ) O(1) O(1)来解决这其中的所有 link.

tricky solution:
tricky solution

一个 node 的所有 children (即 siblings 之间),形成一个双向循环链表,并且这些 children 都存一个 指向其 parent 的指针。parent 随便存一个 “代表”孩子。

现在来试一下 decrease D 的 key。

首先 D 找到 A,发现 D 不是“代表”孩子,既然不代表那就该死死去。nothing changes.
D 顾左右,C-D link → \rightarrow E,E-D link → \rightarrow C. 把自己扣出来,铁锅炖自己,放到 A 旁边, O ( 1 ) O(1) O(1)

而如果要 decreaseKey 的是“代表”孩子,那 只需 A 的指针随便指向“代表”孩子的兄弟就好了。

小节

至此所有堆知识的进阶(graduate)都讲完了。Binary 本身已经是非常简洁高效的数据结构了。后面的 binomial heap 及其他都是在一定应用场景下诞生的更为高效的数据结构。

看起来 Fibonacci heap 无限美好。但回答之前能否起飞的问题——很大概率不能。

因为一个node 存了太多东西了:

  • A pointer to its parent.
  • A pointer to the next sibling.
  • A pointer to the previous sibling.
  • A pointer to an arbitrary child.
  • A bit for whether it’s marked.
  • Its order.
  • Its key.
  • Its element

这些 constant factors 让斐波那契堆实现的优先队列在实际过程中速度不及其它的堆。除非,在一些非常非常大的图上,或者在需要 "tons of d e c r e a s e K e y decreaseKey decreaseKey操作"的网络流问题上。

但理论上 Fibonacci heaps 还是值得去了解的:

  • 首先是分析时使用了 two-tiered potential method——老千层饼了。
  • 再一个是这种 decreaseKey 的思路值得去借鉴。
  • 最后是给 dijkstra 单源点最短路径 和 prim 最小生成树问题给出了理论上的 optimal 边界。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值