Algorithm Search⌘K

Proofs: Smoothsort

These are the human proofs of Smoothsort, at full length.

Smoothsort sorts the array in place full

This proof shows: correctness.

Definitions. A Leonardo tree of order kk at root index rr occupies A[r−L(k)+1…r]A[r - L(k) + 1 \ldots r]. For k≤1k \le 1 it is the node rr. For k≥2k \ge 2 its children are c2=r−1c_2 = r - 1, the root of a tree of order k−2k - 2, and c1=r−1−L(k−2)c_1 = r - 1 - L(k-2), the root of a tree of order k−1k - 1; the sizes add up, since L(k−1)+L(k−2)+1=L(k)L(k-1) + L(k-2) + 1 = L(k). The tree is a heap when each node is at least each of its children. A forest is a list of trees whose segments are consecutive from index 0. We use two invariants for a forest:

  • (H) each tree is a heap;
  • (R) the roots are non-decreasing from left to right.

Lemma 1 (SIFT-DOWN). If both subtrees of a tree are heaps, SIFT-DOWN of its root makes the tree a heap and only permutes its segment.

Proof. This is the sift-down of heapsort, on a tree whose children are given by the formulas above. Each swap exchanges the root with its larger child when the root is smaller; then the old child position holds a value that is at least the other child and its own former subtree, except at the new position of the moving item, where the claim is applied again on a smaller tree. When the loop stops, the moving item is at least its children. □\square

Lemma 2 (RECTIFY). Suppose the trees before tree jj satisfy (H) and (R), and the two subtrees of tree jj (if any) are heaps. Then after RECTIFY(F,j)(F, j), the trees up to tree jj satisfy (H) and (R).

Proof. Let tt be the current tree, starting with t=jt = j, with root xx and, if the order is at least 2, children c1c_1 and c2c_2. Let bb be the largest of xx, c1c_1 and c2c_2. The loop keeps this claim: the trees before tt satisfy (H) and (R); the subtrees of tt are heaps; and each tree after tt, up to jj, is a heap whose root is at least all items of the trees to its left and at least the roots before it. At the start there are no trees after tt, so the claim holds.

If the root pp of tree t−1t - 1 is greater than bb, the loop swaps pp and xx. Now the root of tt is pp, which is greater than c1c_1 and c2c_2, so tree tt is a heap. Since pp was the largest item of the heap t−1t - 1, and the roots before t−1t - 1 are at most pp by (R), the new root pp of tree tt is at least all items to its left. Tree t−1t - 1 now has root xx and subtrees that are heaps, so the claim holds with t−1t - 1 as the current tree.

If p≤bp \le b, or tt is the first tree, the loop stops, and SIFT-DOWN makes tree tt a heap by Lemma 1. Its root is now bb, the largest item of the tree, and b≥pb \ge p, so (R) holds between t−1t - 1 and tt. Between tt and t+1t + 1: the root of t+1t + 1 was set to a root that was larger than all items of tree tt at that time, and tree tt has the same items now. So (R) holds for all trees up to jj. □\square

Lemma 3 (the build step). If the forest of A[0…i−1]A[0 \ldots i-1] satisfies (H) and (R), then after lines L3 to L5 the forest of A[0…i]A[0 \ldots i] does.

Proof. If line L3 joins trees of orders k+1k + 1 and kk, they occupy A[i−L(k+1)−L(k)…i−1]A[i - L(k+1) - L(k) \ldots i - 1], and with the root ii they form a tree of order k+2k + 2 in the layout above, with heaps as subtrees. If line L4 adds a single node, it is a tree with no subtrees. In both cases the earlier trees are unchanged, so Lemma 2 applies with jj the last tree. □\square

Lemma 4 (the removal step). If the forest of A[0…i]A[0 \ldots i] satisfies (H) and (R), then A[i]A[i] is the largest item of A[0…i]A[0 \ldots i], and after lines L7 to L9 the forest of A[0…i−1]A[0 \ldots i-1] satisfies (H) and (R).

Proof. By (H), each root is the largest item of its tree, and by (R) the last root is the largest root. The last root is at index ii, the right end of the prefix. Removing it leaves either no new tree (k≤1k \le 1) or its two subtrees, which are heaps and occupy the end of the prefix in the order left, right. Lemma 2 applied to the left subtree, whose own subtrees are heaps, gives (H) and (R) up to it; then Lemma 2 applied to the right subtree gives them for the whole forest. □\square

Theorem. After SMOOTHSORT(A)(A), the array is sorted, and it holds the input items.

Proof. All changes are swaps, so the multiset of items is unchanged. By Lemma 3 and induction on ii, after the build the forest of A[0…n−1]A[0 \ldots n-1] satisfies (H) and (R). By Lemma 4 and induction downwards on ii, at each step of line L6 the item A[i]A[i] is the largest of A[0…i]A[0 \ldots i], and it is not moved again, because all later steps work inside A[0…i−1]A[0 \ldots i-1]. So for each i≥1i \ge 1, A[i]A[i] is at least each item before it, and the array is sorted. ■\blacksquare

Back to Smoothsort