Algorithm Search⌘K

Proofs: Sink (sift-down) operation

These are the human proofs of Sink (sift-down) operation, at full length.

Sink restores a max-heap, and heapsort with sink sorts full

This proof shows: correctness, termination.

Positions run from 1 to nn. The children of kk are 2k2k and 2k+12k + 1 when they are at most nn. Let T(k)T(k) be the set of positions of the subtree of kk. A pair (q,c)(q, c) with cc a child of qq is in order when ¬ less(q,c)\neg\,\text{less}(q, c), that is, the item at qq is not smaller than the item at cc. The relation less is a strict weak order on the items, so "not smaller" is transitive.

Lemma (SINK). Let k0k_0 be a position such that each pair of T(k0)T(k_0) whose parent is not k0k_0 is in order. Then SINK(k0,n)(k_0, n) ends after at most ⌊lg⁡(n/k0)⌋+1\lfloor \lg(n/k_0) \rfloor + 1 tests of line L1. At the end, each pair of T(k0)T(k_0) is in order, the items of T(k0)T(k_0) are a permutation of the old ones, and no other position changes.

Proof. We show this invariant at each test of line L1:

(I) k∈T(k0)k \in T(k_0). (S1) Each pair of T(k0)T(k_0) whose parent is not kk is in order. (S2) If k≠k0k \ne k_0 and qq is the parent of kk, the item at qq is not smaller than the item at any child of kk. Only positions of T(k0)T(k_0) have changed, by exchanges.

Initialization. At the first test, k=k0k = k_0, (S1) is the hypothesis, and (S2) does not apply.

Maintenance. Assume (I) and 2k≤n2k \le n. After line L3, jj is a child of kk whose item is not smaller than the item of the other child, if any. If line L4 breaks, we treat it below. Else less(k,j)\text{less}(k, j): write xx for the item at kk and yy for the item at jj, so x<yx < y. After line L5, yy is at kk and xx is at jj.

  1. The pair (k,j)(k, j) is in order, since y>xy > x.
  2. The pair (k,s)(k, s) for the other child ss is in order, by the choice of jj.
  3. If k≠k0k \ne k_0, the pair (q,k)(q, k) with qq the parent of kk is in order, since by (S2) the item at qq is not smaller than yy.
  4. The pairs (j,d)(j, d) for the children dd of jj are the ones that (S1) for the new k=jk = j leaves out.

So (S1) holds for jj. For (S2): before the exchange, each pair (j,d)(j, d) was in order by (S1), since j≠kj \ne k, so yy is not smaller than the item at dd, and yy is now at the parent kk of jj. Line L6 sets k←jk \leftarrow j, and (I) holds again.

Termination. Each pass that does not break replaces kk by a child, so ⌊lg⁡(n/k)⌋\lfloor \lg(n/k) \rfloor, the number of levels below kk, drops by exactly 1, and the loop test fails when no level is left. If the test of line L1 fails, kk has no child and (S1) covers all pairs. If line L4 breaks, the item at kk is not smaller than the item at jj, which is not smaller than the item at the other child, so the pairs from kk are in order, and with (S1) all pairs of T(k0)T(k_0) are in order. □\square

Lemma (DEL-MAX). If pq[1…n]pq[1 \ldots n] is a max-heap with n≥1n \ge 1, DEL-MAX returns a largest item and leaves a max-heap of the other n−1n - 1 items. Proof. The root is a largest item, because each item is joined to the root by a chain of pairs in order. After line L8, position 1 holds the old last item and the heap has n−1n - 1 positions. Each pair whose parent is not 1 joins two positions that did not change, so the lemma on SINK with k0=1k_0 = 1 applies. □\square

Theorem (HEAPSORT). HEAPSORT(a[1…n])(a[1 \ldots n]) ends, and then aa is a permutation of its input in non-decreasing order.

Proof. Construction. We claim that after the call of line L12 for kk, the subtree of each position k′≥kk' \ge k is a max-heap. Before the first call, each position k′>⌊n/2⌋k' > \lfloor n/2 \rfloor has no child, so its subtree is a max-heap. At the call for kk, the children 2k2k and 2k+12k + 1 are larger than kk, so their subtrees are max-heaps, and the lemma on SINK applies. The call changes only positions of T(k)T(k), so each subtree T(k′)T(k') with k′>kk' > k is inside T(k)T(k), where all pairs are now in order, or disjoint from it, where nothing changed. After the call for k=1k = 1, a[1…n]a[1 \ldots n] is a max-heap.

Sortdown. Let NN be the input size and mm the current heap size. We show this invariant at each test of line L13:

(H) a[1…m]a[1 \ldots m] is a max-heap, a[m+1…N]a[m+1 \ldots N] is in non-decreasing order, and no item of a[1…m]a[1 \ldots m] is larger than an item of a[m+1…N]a[m+1 \ldots N].

At the first test, m=Nm = N and the tail is empty, so (H) follows from the construction. In a pass with m>1m > 1, line L14 moves the root, a largest item of the heap, to position mm, and sets the heap size to m−1m - 1. By (H), this item is not larger than the items of the old tail, and it is not smaller than any item that stays in the heap. So the new tail a[m…N]a[m \ldots N] is sorted, and the order between heap and tail holds. Each pair of a[1…m−1]a[1 \ldots m-1] whose parent is not 1 is unchanged, so the lemma on SINK with k0=1k_0 = 1 makes a[1…m−1]a[1 \ldots m-1] a max-heap. Thus (H) holds with m−1m - 1.

Termination. Each pass lowers mm by exactly 1, so the loop runs N−1N - 1 times and stops with m≤1m \le 1. Then a[1…m]a[1 \ldots m] has at most one item, which is not larger than the items of the sorted tail, so a[1…N]a[1 \ldots N] is sorted. Exchanges keep the multiset of the items. ■\blacksquare

Back to Sink (sift-down) operation