Algorithm Search⌘K

Proofs: Fibonacci heap

These are the human proofs of Fibonacci heap, at full length.

Amortized bounds of the Fibonacci heap and the degree bound full

This proof shows: time.amortized, space.

We use the invariants (S), (O), (M) and (L) of the correctness proof. Let F0=0F_0 = 0, F1=1F_1 = 1 and Fj=Fj−1+Fj−2F_j = F_{j-1} + F_{j-2}, and let φ=(1+5)/2\varphi = (1 + \sqrt 5)/2, so that φ2=φ+1\varphi^2 = \varphi + 1.

The degree bound

Lemma 1. Let xx be a node, and let y1,…,yky_1, \ldots, y_k be the children of xx in the order in which they were linked to xx, from the earliest. Then y1.degree≥0y_1.degree \ge 0 and yi.degree≥i−2y_i.degree \ge i - 2 for 2≤i≤k2 \le i \le k.

Proof. The first claim is clear. Let i≥2i \ge 2. When LINK made yiy_i a child of xx, the nodes y1,…,yi−1y_1, \ldots, y_{i-1} were already children of xx, so x.degree≥i−1x.degree \ge i - 1. LINK is called only on two roots of the same degree (line L20 of CONSOLIDATE), so then yi.degree≥i−1y_i.degree \ge i - 1. Since that link, yiy_i has stayed a child of xx, and by (L) it has lost at most one child. A node gains children only by LINK, and only while it is a root, so yiy_i has gained none. So yi.degree≥i−2y_i.degree \ge i - 2. □\square

Lemma 2. Fk+2=1+∑i=0kFiF_{k+2} = 1 + \sum_{i=0}^{k} F_i and Fk+2≥φkF_{k+2} \ge \varphi^k for each k≥0k \ge 0.

Proof. Both by induction on kk. For k=0k = 0: F2=1=1+F0F_2 = 1 = 1 + F_0 and F2=1=φ0F_2 = 1 = \varphi^0. For k=1k = 1, F3=2≥φF_3 = 2 \ge \varphi. For the step, Fk+3=Fk+2+Fk+1=1+∑i=0kFi+Fk+1F_{k+3} = F_{k+2} + F_{k+1} = 1 + \sum_{i=0}^{k} F_i + F_{k+1}, and Fk+3=Fk+2+Fk+1≥φk+φk−1=φk−1(φ+1)=φk+1F_{k+3} = F_{k+2} + F_{k+1} \ge \varphi^k + \varphi^{k-1} = \varphi^{k-1}(\varphi + 1) = \varphi^{k+1}. □\square

Lemma 3. A node of degree kk has at least Fk+2≥φkF_{k+2} \ge \varphi^k nodes in its subtree.

Proof. We show size(x)≥Fx.degree+2\mathrm{size}(x) \ge F_{x.degree + 2} for each node xx, by induction on the height of xx. A leaf has degree 0 and size 1=F21 = F_2. Let xx have degree k≥1k \ge 1 and the children y1,…,yky_1, \ldots, y_k as in Lemma 1. Each child has a smaller height than xx, so the claim holds for it. By this and Lemma 1, the subtree of yiy_i has at least Fyi.degree+2≥FiF_{y_i.degree + 2} \ge F_i nodes for i≥2i \ge 2, since the Fibonacci numbers do not decrease, and y1y_1 adds at least 1 node. Counting xx too,

size(x)≥2+∑i=2kFi=1+∑i=0kFi=Fk+2,\mathrm{size}(x) \ge 2 + \sum_{i=2}^{k} F_i = 1 + \sum_{i=0}^{k} F_i = F_{k+2},

using F0=0F_0 = 0, F1=1F_1 = 1 and Lemma 2. The second inequality of the claim is Lemma 2. □\square

Corollary. In a heap of n≥1n \ge 1 nodes, each degree is at most D(n)=⌊log⁡φn⌋D(n) = \lfloor \log_\varphi n \rfloor.

Proof. A node of degree kk has n≥φkn \ge \varphi^k by Lemma 3, so k≤log⁡φnk \le \log_\varphi n. □\square

The amortized costs

Let t(H)t(H) be the number of roots and m(H)m(H) the number of marked nodes, and let

Φ(H)=t(H)+2 m(H)≥0,\Phi(H) = t(H) + 2\,m(H) \ge 0,

with Φ=0\Phi = 0 for the empty heap. Scale the unit of work so that each line of the main block that is not a loop, and each iteration of a loop, costs at most 1 unit, and scale Φ\Phi by the same constant cc. Then for each sequence of operations from the empty heap, the total actual cost is at most the sum of the amortized costs c^=cactual+ΔΦ\hat c = c_{\text{actual}} + \Delta \Phi, because Φ\Phi starts at 0 and stays non-negative.

Insert. O(1)O(1) actual work, Δt=1\Delta t = 1, Δm=0\Delta m = 0. So c^=O(1)\hat c = O(1).

Union. O(1)O(1) actual work. The potential of the union is the sum of the two potentials, so ΔΦ=0\Delta \Phi = 0, and c^=O(1)\hat c = O(1).

Find-min. O(1)O(1), with no change.

Extract-min. Let t=t(H)t = t(H) before the call. Line L11 adds at most D(n)D(n) roots, the children of zz, and line L12 removes zz. So CONSOLIDATE starts with at most t+D(n)−1t + D(n) - 1 roots. Each iteration of the loop of line L18 costs O(1)O(1) plus O(1)O(1) for each LINK, and each LINK removes one root, so there are fewer links than roots. Lines L26 to L30 go over at most D(n)+1D(n) + 1 entries of TT, by the corollary. The actual cost is O(t+D(n))O(t + D(n)). At the end, the roots have pairwise different degrees in {0,…,D(n)}\{0, \ldots, D(n)\}, so t(H)≤D(n)+1t(H) \le D(n) + 1, and no mark is set. So

c^≤c1(t+D(n))+c (D(n)+1−t)=O(D(n))\hat c \le c_1 (t + D(n)) + c\,(D(n) + 1 - t) = O(D(n))

when c≥c1c \ge c_1.

Decrease-key. Let the call do q≥0q \ge 0 cuts in total, counting the cut of line L37 and the cuts of line L45. The actual cost is O(q+1)O(q + 1). The qq cuts add qq roots. Each cut of line L45 removes the mark of a marked node, by line L41, and there are at least q−1q - 1 such cuts when q≥1q \ge 1. At most one mark is set, at line L44. So

ΔΦ≤c (q+2 (1−(q−1)))=c (4−q),\Delta \Phi \le c\,\bigl(q + 2\,(1 - (q - 1))\bigr) = c\,(4 - q),

and c^≤c1(q+1)+c(4−q)=O(1)\hat c \le c_1(q + 1) + c(4 - q) = O(1) when c≥c1c \ge c_1. If q=0q = 0, the change is 0 and the cost is O(1)O(1).

Delete. One decrease-key and one extract-min, so c^=O(1)+O(D(n))=O(D(n))\hat c = O(1) + O(D(n)) = O(D(n)).

Theorem. For each sequence of operations on Fibonacci heaps that starts from empty heaps, the total time is at most O(1)O(1) for each insert, find-min, union and decrease-key, plus O(log⁡n)O(\log n) for each extract-min and delete, where nn is the size of the heap at that time. The space is O(n)O(n).

Proof. By the cases above, the amortized costs are O(1)O(1) and O(D(n))O(D(n)), and D(n)≤log⁡φn=O(log⁡n)D(n) \le \log_\varphi n = O(\log n) by the corollary. Each node has a fixed number of fields, and the table TT has at most D(n)+1D(n) + 1 entries. ■\blacksquare

The operations of a Fibonacci heap keep its invariants and return a minimum full

This proof shows: correctness, termination.

We write N(H)\mathcal{N}(H) for the set of nodes of the trees of HH, and K(H)K(H) for the multiset of their keys. The structure invariant (S) says: the trees are disjoint rooted trees on N(H)\mathcal{N}(H); the roots form the root list and have x.p=nilx.p = \text{nil}; the children of each node xx form its child list, each child cc has c.p=xc.p = x, and x.degreex.degree is the number of children; and H.n=∣N(H)∣H.n = |\mathcal{N}(H)|. The other invariants are

  • (O) x.p.key≤x.keyx.p.key \le x.key for each non-root node xx;
  • (M) H.min=nilH.min = \text{nil} if H.n=0H.n = 0, and else H.minH.min is a root with H.min.key≤x.keyH.min.key \le x.key for each x∈N(H)x \in \mathcal{N}(H);
  • (L) each non-root node xx has lost no child since it last became a child (by LINK) if x.mark=falsex.mark = \text{false}, and exactly one if x.mark=truex.mark = \text{true}.

A node loses a child when a CUT removes that child from its child list. We show that each operation keeps (S), (O), (M) and (L), and changes K(H)K(H) as the priority queue type says.

Lemma 1 (LINK). Let xx and yy be two different roots with x.key≤y.keyx.key \le y.key. Then LINK(H,y,x)(H, y, x) keeps (S) and (O) and does not change K(H)K(H); afterwards yy is a non-root with no lost child and no mark, so (L) holds at yy.

Proof. Line L31 takes yy out of the root list and line L32 puts it in the child list of xx with y.p=xy.p = x and adds 1 to x.degreex.degree. So the trees stay disjoint and (S) holds. The only new edge is (x,y)(x, y), and x.key≤y.keyx.key \le y.key, so (O) holds. Line L33 clears the mark, and yy has just become a child, so it has lost no child since. No node is added or removed. □\square

Lemma 2 (CUT). Let xx be a child of yy. Then CUT(H,x,y)(H, x, y) keeps (S) and (O) and does not change K(H)K(H). It makes xx a root, and yy loses the child xx.

Proof. Line L40 removes xx from the child list of yy and lowers y.degreey.degree by 1, and line L41 puts xx in the root list with x.p=nilx.p = \text{nil}. The subtree of xx comes along unchanged. (S) holds. An edge was removed and none was added, so (O) holds. □\square

Lemma 3 (CASCADING-CUT). Assume (S) and (O), and assume that (L) holds at each node except yy, and that yy, if it is not a root, has lost exactly one more child than (L) allows for its mark. Then CASCADING-CUT(H,y)(H, y) stops, keeps (S) and (O), restores (L), and does not change K(H)K(H).

Proof. By induction on the depth of yy. If yy is a root (line L43), (L) says nothing about yy, and the procedure stops. Else let z=y.pz = y.p. If yy is not marked, it had lost no child, and now it has lost one. Line L44 marks it, so (L) holds at yy, and the procedure stops. If yy is marked, it had lost one child, and now it has lost two. Line L45 cuts yy from zz. By Lemma 2, (S) and (O) hold, yy is a root, so (L) says nothing about it, and zz has lost one more child. The depth of zz is one less than the depth of yy, so by induction the call CASCADING-CUT(H,z)(H, z) stops and restores (L). □\square

Insert. Line L1 makes xx a tree of one node, and line L2 adds it to the root list, so (S) holds after line L4, and (O) holds because there is no new edge. Line L3 keeps (M), since the new minimum is the smaller of the old minimum and x.keyx.key. No node lost a child, so (L) holds. K(H)K(H) gains x.keyx.key.

Union. Line L5 joins the two root lists, so the trees of H2H_2 become trees of H1H_1, and lines L7 and L8 keep the counts. (S), (O) and (L) hold, since they hold in each heap and no edge changes. A minimum of K(H1)∪K(H2)K(H_1) \cup K(H_2) is the smaller of the two minima, which line L6 picks, so (M) holds. H2H_2 becomes empty, which satisfies all invariants.

Extract-min. Let H.n≥1H.n \ge 1. By (M), z=H.minz = H.min holds a minimum of K(H)K(H). Line L11 makes each child of zz a root. These children were non-roots and become roots, so (L) says nothing about them now; the edges from zz to them are gone, and (O) loses edges only. Line L12 removes zz, which is a root with no children left. So K(H)K(H) loses one copy of its minimum, and (S) holds with H.nH.n lowered by 1 at line L15. If H.n=1H.n = 1 before, the heap is now empty, and line L13 sets (M). Else CONSOLIDATE runs.

Lemma 4 (CONSOLIDATE). Assume (S), (O) and (L) and that the root list is not empty. Then CONSOLIDATE stops, keeps (S), (O) and (L), does not change K(H)K(H), makes the degrees of the roots pairwise different, and sets (M).

Proof. Let RR be the list of roots at line L18, taken once before the loop. We claim that, before each iteration of line L18, the set QQ of roots that are entries of TT, together with the roots of RR not yet visited, is the set of all roots, each entry T[d]T[d] is a root of degree dd, and the entries have pairwise different degrees.

At the start, TT is empty and Q∪RQ \cup R is the root list. In an iteration with ww, the inner loop keeps this claim: xx is a root of degree dd that is not in TT; if T[d]=yT[d] = y is set, then yy is another root of degree dd, and after line L22, x.key≤y.keyx.key \le y.key. By Lemma 1, LINK keeps (S), (O) and (L), and makes yy a child of xx; then xx has degree d+1d + 1, and line L24 clears T[d]T[d]. Each LINK lowers the number of roots by 1, so the inner loop stops after at most ∣R∣−1|R| - 1 links in total. When it stops, T[d]T[d] is empty and line L25 stores xx there. So the claim holds after the iteration, with ww visited. When the loop ends, the roots are exactly the entries of TT, with pairwise different degrees.

Lines L26 to L29 rebuild the root list from these entries, and line L30 keeps the smallest key seen, so at the end H.minH.min is a root of least key among the roots. By (O) and the global form of the heap property, each key is at least the key of its root, so (M) holds. No node is added or removed, so K(H)K(H) is unchanged. □\square

So after line L16, the invariants hold, K(H)K(H) has lost one minimum, and the returned node zz holds that minimum.

Decrease-key. Let k≤x.keyk \le x.key, as line L34 checks. Line L35 lowers x.keyx.key. The edges from xx to its children stay ordered, because x.keyx.key only got smaller. The only edge that may break (O) is (y,x)(y, x), where y=x.py = x.p. If y=nily = \text{nil} or y.key≤x.keyy.key \le x.key, (O) holds. Else line L37 cuts xx; by Lemma 2, (S) and (O) hold, and yy has lost one child. So the hypothesis of Lemma 3 holds at yy, and line L38 restores (L). In both cases, line L39 keeps (M): the keys other than x.keyx.key did not change, xx is a root if its key is now below its parent, and else x.key≥y.key≥H.min.keyx.key \ge y.key \ge H.min.key. K(H)K(H) has the old key of xx replaced by kk.

Delete. Line L46 decreases x.keyx.key to a value below all keys, so by the case above xx becomes a root and line L39 sets H.min=xH.min = x. Line L47 then removes xx. So K(H)K(H) loses x.keyx.key, and the invariants hold.

Termination. Each operation except CONSOLIDATE and CASCADING-CUT has no loop or a loop over a finite list. Lemma 3 and Lemma 4 show that these two stop.

Theorem. Starting from the empty heap, after each sequence of operations the invariants (S), (O), (M) and (L) hold, FIND-MIN and EXTRACT-MIN return a node of minimum key, and the multiset K(H)K(H) is the one that the priority queue type gives for the same sequence.

Proof. The empty heap satisfies all invariants. Each operation keeps them and changes K(H)K(H) as the type says, by the cases above. By (M), FIND-MIN returns a node of minimum key, and the case of EXTRACT-MIN shows the same for it. ■\blacksquare

Back to Fibonacci heap