Proofs: Heapsort
These are the human proofs of Heapsort, at full length.
Heapsort sorts the array and keeps its items full
This proof shows: correctness, termination.
We write for the parent of an index . The part is a heap when for each with . The subtree of in a heap of size is the set of indices less than that have as an ancestor, together with . Each step of the algorithm is an exchange of two items, so the multiset of items of never changes. We prove only the order.
Lemma 1 (SIFT-DOWN). Let . Assume that each pair with in the subtree of and satisfies , except the pairs whose parent is . Then SIFT-DOWN stops after at most steps of its loop, and after it the subtree of satisfies the heap order. It changes only items of the subtree of .
Proof. Let be the value of at the call, and let be the item . We use this invariant at the test of line L5, for the current index :
(S) Each pair with in the subtree of and is in heap order, except perhaps the pairs whose parent is . If , then is at least each child of . The item at is .
Initialization. At the call , so the first statement is the assumption, and the second statement does not apply.
Maintenance. Assume (S) and . Lines L6 and L7 set to a child of with the largest item among the children of . If , line L8 returns, and is at least each child, so all pairs with parent are in order. Together with (S), the full subtree is in heap order. Otherwise . Line L9 exchanges them. Now the item at is the old , which is at least the item of the other child of , by the choice of , and at least , the new item at . If , the old is at most by the second statement of (S), so the pair stays in order. The children of were at most the old , because was in order by (S), so after line L10 sets , the parent of the new holds the old , which is at least each child of the new . Only the pairs with parent can now be out of order. So (S) holds for the new .
Termination. Each step moves to a child, so it increases the depth of by exactly 1. The depth of an index less than is at most . So the loop runs at most times. If it stops at line L5, then has no child less than , so there are no pairs with parent , and (S) gives the heap order of the whole subtree. If it stops at line L8, the maintenance step showed the heap order. Each exchange is between and a child of , both in the subtree of .
Lemma 2 (build phase). After line L1, is a heap.
Proof. We use the invariant: before the call for , the subtree of each index with is in heap order. At the start . Each has , so it has no child, and its subtree is in heap order. Before the call for , both children of are greater than , so their subtrees are in heap order. These are all the pairs of the subtree of whose parent is not , so Lemma 1 applies, and after the call the subtree of is in heap order. The call changes only the subtree of , so the subtree of each that is not inside the subtree of is unchanged. The subtrees of the indices inside the subtree of are parts of a subtree in heap order, so they are in heap order too. So the invariant holds for . After the call for , the subtree of 0, which is the whole array, is in heap order. If the loop does not run, and an array of at most one item is a heap.
Theorem. HEAPSORT stops, and after it is sorted in non-decreasing order and holds the same multiset of items.
Proof. We use this invariant at the test of line L2, for the current value of :
(H) is a heap. is sorted in non-decreasing order. Each item of is at most each item of .
Initialization. Before the first step, . By Lemma 2, is a heap. The other two parts of (H) are about an empty range.
Maintenance. Assume (H) for . In a heap, each item is at most the item of its parent, so by induction on the depth each item is at most . So is a largest item of . Line L3 moves it to . It is at least each item of , and by (H) at most each item of . So is sorted, and each item of is at most each item of . After the exchange, each pair of whose parent is not 0 is still in heap order, because only the item at index 0 changed. So Lemma 1 applies to SIFT-DOWN, and after line L4, is a heap. SIFT-DOWN changes only indices less than , so the sorted part is unchanged. Then the loop sets , and (H) holds.
Termination. The loop of line L2 runs times, and each call of SIFT-DOWN stops by Lemma 1. After the last step , and (H) says that is sorted and that is at most each item of it. So is sorted. If the loop does not run, and the array is sorted.