Algorithm Search⌘K

Proofs: Cycle sort

These are the human proofs of Cycle sort, at full length.

Cycle sort sorts the array and writes each misplaced position exactly once full

This proof shows: correctness, termination.

Let B[0…n−1]B[0 \ldots n-1] be the input in sorted order. Call a position qq final when A[q]=B[q]A[q] = B[q], where == means that neither item is less than the other. For 0≤s≤n−10 \le s \le n-1 let MsM_s be the multiset B[s…n−1]B[s \ldots n-1].

Outer invariant. At the start of the iteration of line L2 for ss:

(O) A[0…s−1]=B[0…s−1]A[0 \ldots s-1] = B[0 \ldots s-1], and the multiset of A[s…n−1]A[s \ldots n-1] is MsM_s.

It holds for s=0s = 0 because AA is a permutation of BB.

Lemma 1 (POSITION). Let cc be the number of items of A[s+1…n−1]A[s+1 \ldots n-1] that are less than xx, and suppose the multiset of A[s+1…n−1]A[s+1 \ldots n-1] plus xx is MsM_s. Then POSITION(A,s,x)(A, s, x) returns s+cs + c, and B[s+c],…,B[s+c+m−1]B[s+c], \ldots, B[s+c+m-1] are the copies of xx in MsM_s, where m≥1m \ge 1 is their number.

Proof. Lines L13 to L15 add 1 for each item of A[s+1…n−1]A[s+1 \ldots n-1] less than xx, so they return s+cs + c. The items of MsM_s less than xx are all in A[s+1…n−1]A[s+1 \ldots n-1], because xx is not less than itself, so exactly cc items of MsM_s are less than xx. In the sorted order B[s…n−1]B[s \ldots n-1] of MsM_s they take the places s,…,s+c−1s, \ldots, s+c-1, and the mm copies of xx come next. □\square

Inner invariant. Fix ss with (O), and let x0=A[s]x_0 = A[s] at line L3. If line L5 continues, then c=0c = 0 for x0x_0, so by Lemma 1 B[s]B[s] is a copy of x0x_0, and (O) holds for s+1s + 1. Otherwise, at each test of line L7 of this cycle:

(I) The multiset of A[s+1…n−1]A[s+1 \ldots n-1] plus xx is MsM_s; A[s]A[s] still holds x0x_0; each final position of A[s+1…n−1]A[s+1 \ldots n-1] at the start of the cycle is still final; and pp is the value s+cs + c of Lemma 1 for the held xx.

At the first test, (I) holds by line L4 and because nothing has been written.

Lemma 2 (one step). Assume (I) at line L7. Then line L7 stops at a position qq in the block s+c,…,s+c+m−1s+c, \ldots, s+c+m-1 of xx with A[q]≠xA[q] \ne x, and after line L8, position qq is final, no final position of A[s+1…n−1]A[s+1 \ldots n-1] has lost its item, and the multiset of A[s+1…n−1]A[s+1 \ldots n-1] plus the new xx is again MsM_s if q≠sq \ne s.

Proof. First let c=0c = 0. Then xx is a smallest item of MsM_s, and x≠x0x \ne x_0: if x0x_0 were a copy of xx, it would also be a smallest item of MsM_s, which would give c=0c = 0 for x0x_0, and line L5 would have continued. So line L7 stops at once at q=sq = s. Now let c≥1c \ge 1, so the block lies in s+1,…,n−1s+1, \ldots, n-1. The array part A[s+1…n−1]A[s+1 \ldots n-1] holds m−1m - 1 copies of xx, because the held item is the mm-th copy, so some position of the block does not hold xx, and line L7, which moves right from the first position of the block past copies of xx only, stops at the first such position qq. In both cases B[q]B[q] is a copy of xx by Lemma 1, so after line L8 places xx at qq, the position qq is final. Before the write A[q]≠x=B[q]A[q] \ne x = B[q], so qq was not final, and no final item was moved. If q≠sq \ne s, the write exchanges an item of A[s+1…n−1]A[s+1 \ldots n-1] with the held item, which keeps the multiset of the two together. □\square

Termination of a cycle. By Lemma 2, each write at a position q≠sq \ne s turns a position of A[s+1…n−1]A[s+1 \ldots n-1] that was not final into a final one, and no final position becomes not final. There are n−1−sn - 1 - s positions there, so after at most n−1−sn - 1 - s such writes the next write is at q=sq = s, and line L10 ends the loop. Between writes, line L11 sets pp by Lemma 1, so (I) holds at the next test of line L7.

End of a cycle. The last write is at q=sq = s, which by Lemma 2 needs c=0c = 0, so the held item is a smallest item of MsM_s and becomes B[s]B[s]. The stale copy x0x_0 is now the held item and is dropped. Before this write, the array part A[s+1…n−1]A[s+1 \ldots n-1] plus the held item was MsM_s, so after it A[s…n−1]A[s \ldots n-1] is MsM_s, with A[s]=B[s]A[s] = B[s]. So (O) holds for s+1s + 1.

Conclusion. The loop of line L2 ends after s=n−2s = n - 2. By (O) for s=n−1s = n - 1, A[0…n−2]=B[0…n−2]A[0 \ldots n-2] = B[0 \ldots n-2] and A[n−1]A[n-1] is the one item of Mn−1={B[n−1]}M_{n-1} = \{B[n-1]\}. So A=BA = B, and the array is sorted.

Writes. Each write makes a position final that was not final, and no position stops being final, except that A[s]A[s] is not final while it holds the stale copy x0≠B[s]x_0 \ne B[s], and it is written once, at the end of its cycle. A position that is final at the start of the run is never written: a position q>sq > s is written only when it is not final, and a start ss that is final makes line L5 continue. So each position is written at most once, exactly the positions that are not final at the start are written, and the return value of line L12 is the number of positions ii with A[i]≠B[i]A[i] \ne B[i] in the input. Any algorithm that sorts the array must write each of these positions at least once, so the number is the least possible. ■\blacksquare

Back to Cycle sort