Algorithm Search⌘K

Proofs: Flashsort

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

Flashsort sorts its input full

This proof shows: correctness, termination.

Assume n≥2n \ge 2 and lo<hilo < hi; otherwise lines L1 and L2 return an array that is already sorted. The class map KK is non-decreasing, with K(lo)=0K(lo) = 0 and K(hi)=m−1K(hi) = m - 1, and 0≤K(x)≤m−10 \le K(x) \le m - 1 for lo≤x≤hilo \le x \le hi. Let C[k]C[k] be the count of line L4, end[k]=C[0]+⋯+C[k]end[k] = C[0] + \cdots + C[k] the value of top[k]top[k] after line L5, and start[k]=end[k]−C[k]start[k] = end[k] - C[k]. The blocks [start[k],end[k])[start[k], end[k]) are disjoint, in the order of kk, and cover [0,n)[0, n).

Call position pp placed if p∈[top[k],end[k])p \in [top[k], end[k]) for the class kk whose block contains pp. Placed positions hold keys of the class of their block, as we show.

Invariant (P). At each test of line L7:

(P1) each placed position pp in block kk holds a key of class kk; (P2) for each kk, the number of keys of class kk at positions that are not placed is top[k]−start[k]top[k] - start[k]; (P3) every position p<ip < i is placed; (P4) AA is a permutation of the input.

At the start no position is placed, top[k]=end[k]top[k] = end[k], and there are C[k]=end[k]−start[k]C[k] = end[k] - start[k] keys of class kk, so (P1) to (P4) hold with i=0i = 0.

Line L8. Let i<ni < n, let bb be the block that contains ii, and let k=K(A[i])k = K(A[i]). If ii is placed, then k=bk = b by (P1), and i≥top[b]i \ge top[b], so line L8 moves on, and (P3) holds for i+1i + 1. If ii is not placed, then start[b]≤i<top[b]start[b] \le i < top[b]. By (P3), all positions of [start[b],i)[start[b], i) are placed, and since the placed positions of block bb are [top[b],end[b])[top[b], end[b]), this means i=start[b]i = start[b]. Now k≥bk \ge b: if k<bk < b, then the block of kk lies before ii and is fully placed by (P3), so top[k]=start[k]top[k] = start[k], and by (P2) there is no key of class kk at a position that is not placed, but A[i]A[i] is one. If k=bk = b, then i<top[k]i < top[k]. If k>bk > b, then i<end[b]≤start[k]≤top[k]i < end[b] \le start[k] \le top[k]. So in both cases line L8 does not skip, and line L9 starts a cycle with x=A[i]x = A[i].

The cycle of line L10. During the cycle, position ii is treated as empty: its content is the leader, which is also in hand. We claim that before each step, the key in hand xx is a key of some class kk that is not yet placed, and top[k]−1top[k] - 1 is a position that is not placed, at or after ii. By (P2) applied with xx counted at its old position, top[k]−start[k]≥1top[k] - start[k] \ge 1, so top[k]−1≥start[k]top[k] - 1 \ge start[k] is in block kk and not placed. If kk's block lies before ii, it is fully placed by (P3), which contradicts the existence of xx, so top[k]−1≥itop[k] - 1 \ge i. The step decreases top[k]top[k], so the position top[k]top[k] is now placed and holds xx, a key of class kk: (P1) holds. The key that was there was at a position that was not placed; it is now in hand, and (P2) holds for its class, because it is counted as not placed until it is put down. If the position was ii, the key that was there is the stale copy of the leader, which is already accounted for, and the cycle ends with A[i]A[i] placed. Each step places one more position, and there are finitely many, so the cycle ends. The cycle can end only at position ii, so when it ends, ii is placed and holds a key of its block; the leader was put down in the cycle at its own place; and each key of the input is again at exactly one position, so (P4) holds. Then (P3) holds for i+1i + 1 at the next test.

Termination of the loop. Each turn of line L7 either increases ii or runs a cycle that places at least one position and then the next turn increases ii at line L8. So the loop ends with i=ni = n.

After the loop. By (P3) every position is placed, and by (P1) block kk holds keys of class kk. Since KK is non-decreasing, a key of a lower class is not larger than a key of a higher class. So the array is a permutation of the input in which every inversion is between two keys of the same block.

Line L11. Insertion sort sorts any array, so the result is sorted. ■\blacksquare

Back to Flashsort