Algorithm Search⌘K

Proofs: Sift-down

These are the human proofs of Sift-down, at full length.

Sift-down restores the heap property in a subtree full

This proof shows: correctness, termination.

The children of jj are 2j+12j+1 and 2j+22j+2 when they are less than nn. Let T(j)T(j) be the set of indices in the subtree of jj. An edge (q,c)(q, c) is a pair with cc a child of qq. It is right when A[q]≤A[c]A[q] \le A[c]. Let i0i_0 be the input index.

Theorem. Assume 0≤i0<n0 \le i_0 < n and that each edge of T(i0)T(i_0) whose parent is not i0i_0 is right. Then SIFT-DOWN(A,i0,n)(A, i_0, n) ends after at most h(i0)+1h(i_0) + 1 iterations, where h(i0)h(i_0) is the number of levels below i0i_0. At the end, all edges of T(i0)T(i_0) are right, the items of T(i0)T(i_0) are a permutation of the old ones, and no cell outside T(i0)T(i_0) has changed.

Proof. We show that this invariant holds each time line L2 starts:

(I) i∈T(i0)i \in T(i_0). (D1) Each edge of T(i0)T(i_0) whose parent is not ii is right. (D2) If i≠i0i \ne i_0 and qq is the parent of ii, then A[q]≤A[d]A[q] \le A[d] for each child dd of ii. Only cells of T(i0)T(i_0) have changed, by swaps.

Initialization. At the first iteration, i=i0i = i_0. Then (D1) is the hypothesis, (D2) does not apply, and nothing has changed.

Maintenance. Assume (I). If line L3 or line L6 returns, we treat it under termination. Else ii has a child, lines L4 and L5 set cc to a child of ii with A[c]≤A[d]A[c] \le A[d] for each child dd of ii, and A[c]<A[i]A[c] < A[i]. Write a=A[i]a = A[i] and b=A[c]b = A[c] before line L7, so b<ab < a. After line L7, A[i]=bA[i] = b and A[c]=aA[c] = a. We check each edge with an end at ii or cc. All other edges keep both values.

  1. The edge (i,c)(i, c): A[i]=b<a=A[c]A[i] = b < a = A[c], so it is right.
  2. The edge (i,s)(i, s) to the other child ss of ii, if there is one: b≤A[s]b \le A[s] by the choice of cc, so it is right.
  3. The edge (q,i)(q, i) from the parent qq of ii, if i≠i0i \ne i_0: by (D2), A[q]≤bA[q] \le b, because cc is a child of ii. So it is right. If i=i0i = i_0, this edge is not in T(i0)T(i_0), and we do not need it.
  4. The edges (c,d)(c, d) for the children dd of cc: these are the edges that (D1) for the new index cc leaves out.

So each edge of T(i0)T(i_0) whose parent is not cc is right, which is (D1) for cc. For (D2) with the new index cc, whose parent is ii: before the swap, each edge (c,d)(c, d) was right by (D1), since c≠ic \ne i, so b≤A[d]b \le A[d]. The new value at ii is bb, so A[i]≤A[d]A[i] \le A[d] for each child dd of cc. A swap of two cells of T(i0)T(i_0) keeps the multiset of T(i0)T(i_0), and c∈T(i0)c \in T(i_0). Line L8 sets i←ci \leftarrow c, so (I) holds at the next iteration.

Termination. Each iteration that does not return moves ii to a child, so the number of levels below ii drops by exactly 1. The number of levels below i0i_0 is h(i0)h(i_0), and a node with no level below it is a leaf, at which line L3 returns. So there are at most h(i0)h(i_0) iterations that do not return, and one more that returns.

If line L3 returns, ii is a leaf, so there is no edge with parent ii, and (D1) covers all edges of T(i0)T(i_0). If line L6 returns, then A[i]≤A[c]≤A[d]A[i] \le A[c] \le A[d] for each child dd of ii, so the edges with parent ii are right, and with (D1) all edges of T(i0)T(i_0) are right. By (I), only cells of T(i0)T(i_0) changed, and their items are a permutation of the old ones. ■\blacksquare

EXTRACT-MIN. Let A[0…n−1]A[0 \ldots n-1] be a min-heap with n≥1n \ge 1. Line L9 saves the root, which is a smallest item because each item is reached from the root by right edges. After line L10 the heap has n−1n - 1 items, and each edge whose parent is not 00 joins two cells that did not change, so it is right. If n−1>0n - 1 > 0, the theorem with i0=0i_0 = 0 makes the whole array a min-heap. The items are the old items less one copy of the returned minimum.

Increase-key. If AA is a min-heap and the value at ii grows, each edge of T(i)T(i) whose parent is not ii keeps both values, so the theorem applies to T(i)T(i). The edge from the parent qq of ii stays right: the final value at ii is the new value, which is larger than the old one, or a value from T(i)T(i), which was at least the old A[i]≥A[q]A[i] \ge A[q].

Floyd's construction. Call SIFT-DOWN(A,i,n)(A, i, n) for i=⌊n/2⌋−1,…,0i = \lfloor n/2 \rfloor - 1, \ldots, 0. Claim: after the call for ii, the subtrees of i,i+1,…,n−1i, i+1, \ldots, n-1 are min-heaps. The indices j≥⌊n/2⌋j \ge \lfloor n/2 \rfloor are leaves, so the claim holds before the first call. When the call for ii starts, its children are larger indices, so their subtrees are heaps, which is the hypothesis of the theorem. The call changes only cells of T(i)T(i), and for j>ij > i the subtree T(j)T(j) is either inside T(i)T(i), where the call leaves all edges right, or disjoint from it, where nothing changes. So the claim holds after the call, and after the call for 00 the whole array is a heap.

Back to Sift-down