Proofs: Hollow heap
These are the human proofs of Hollow heap, at full length.
The hollow heap operations keep the heap order and find the minimum full
This proof shows: correctness, termination.
We use the notation of the page. The child list of a node starts at , follows the sibling pointers, and ends at nil or right after the first node with . An edge goes from to each node of its child list. A heap with root satisfies the following invariants.
- (G) The nodes and edges form a finite acyclic graph in which every node is a descendant of .
- (P) Each node other than has one or two parents. A node with two parents is hollow, is one of them, is the last node of the child list of , and its sibling pointer continues the child list of the other parent. A node with one parent, or none, has .
- (O) For each edge from to , .
- (R) The heap is empty, or is full.
- (I) For each item in the heap, is a full node whose item is ; each full node holds an item of the heap.
Lemma 1. If (G), (O), (R) and (I) hold, the item of has the minimum key.
Proof. Each item is in a full node by (I), which is a descendant of by (G). The keys do not decrease along each path from , by (O).
Lemma 2. LINK of two roots of disjoint heaps returns a root whose descendants are those of and , and keeps (O), (P) and (G).
Proof. The loser becomes the first child of the winner : its sibling pointer is set to the old first child of , so the child list of gains at its front and keeps its old end. The only new edge goes from to , with by the test of line L1. was a root, so it now has one parent, and its is nil by (P). No cycle is made, since is not a descendant of in disjoint heaps.
Insert, meld and decrease-key
INSERT makes a full node of rank 0 with no children and links it with ; MELD links two roots. By Lemma 2 the invariants hold, and the new root is full, since both roots were full.
DECREASE-KEY with . If is the root, setting its key keeps (O), since the key went down and the root has no parents. Else is full and is not the root, so by (P) it has one parent and . Lines L8 to L11 make with the item and the key , make hollow, and make the only node of the child list of , with ; the sibling pointer of still continues the list of its first parent. So has two parents and meets (P). The new edge from to has , and the key of is unchanged, so (O) holds. Now is in the full node only, which gives (I). is a root, and line L12 links it with , so by Lemma 2 (G) holds again. The new root is or , both full.
Delete
Line L13 makes hollow and removes , which keeps (I), (G), (O) and (P). If is still full, (R) holds and we are done. Else the loop runs. Call a node destroyed if it enters . The loop keeps the following.
(L1) Each node in , or destroyed, is hollow and has no parent that is not destroyed. (L2) Each node that is not destroyed has a parent that is not destroyed, or is a full root in a tree of a root in , and each node of a tree of that is not a root of has one parent. (L3) For a node that is not destroyed, is nil or a node that is not destroyed, and (P) holds for with respect to its parents that are not destroyed, except that may still be in the list of the node under scan.
The cases of a child of . The node is hollow and all its parents are destroyed, by (L1).
- is full. By (P), has the one parent . It becomes a root. Each ranked link in line L22 links two roots of trees in , which are disjoint, so by Lemma 2 the result is a tree with a full root that is again in and (O) holds on the new edge. So (L2) holds for .
- is hollow and . By (P) and (L3), was its only parent that is not destroyed, so it has none now, and line L19 puts it into , which keeps (L1).
- is hollow and . Then has two parents, and . If , then is the last node of the list of , so the scan stops; its sibling pointer continues the list of , and with it now has the one parent , as (P) asks. If , then is the first parent; setting the sibling pointer of to nil ends the list of at , as before, and with it has the one parent . The scan of goes on with the sibling read before the change.
So the scan of visits every node of its child list. After it, is destroyed and no node that is not destroyed points to it as a parent: every child of was handled above.
After the loop. is empty. Let be a node that is not destroyed. Walk from to a parent that is not destroyed, while there is one. The walk ends, by (G), at a node with no parent that is not destroyed. If were hollow, then when the scan of its last destroyed parent reached it, its was nil, and it entered , so it was destroyed; this is false. So is full, and it is a root of a tree in or below one, by (L2). Hence every node that is not destroyed is in a tree of a root of , and in particular so is every full node, since destroyed nodes are hollow by (L1). The links of lines L25 and L26 join the roots of into one tree, by Lemma 2, whose root is full, being a root of . If is empty, no full node is left and the heap is empty. So (G), (O), (P) and (R) hold, and (I) holds, since no full node was changed.
DELETE-MIN reads the item of , which is a minimum by Lemma 1, and deletes it.
Termination
INSERT, MELD and DECREASE-KEY do a constant number of steps. In DELETE, a node enters only when the scan of its last remaining parent reaches it, and a scanned node is destroyed, so each node enters at most once and the outer loop runs at most once per node of the finite graph. Each child list is finite and is scanned once. Each iteration of the inner loop of line L21 removes one root from , so it runs at most times. The final loop runs once per root in . So every operation ends.
Together with Lemma 1, the invariants show that FIND-MIN and DELETE-MIN return an item of minimum key, and that each operation leaves a valid hollow heap that holds exactly the items inserted and not yet deleted, with their current keys.