Proofs: Three-way radix quicksort
These are the human proofs of Three-way radix quicksort, at full length.
Three-way radix quicksort sorts strings in lexicographic order full
This proof shows: correctness, termination.
Let for and otherwise, with less than every character. Call a range valid at if its strings have length at least and agree on their first characters.
Fact 1. Let and agree on their first characters, with . If then . If then . If then and agree on characters.
Proof. If , then is a proper prefix of . If , then is the first index where they differ. The last two cases follow from the definition.
Fact 2 (partition). At line L4 the following holds: for ; for ; for ; and the range is a permutation of its values at line L2.
Proof. Before the first test, and , and has the value , so the equal part is and the other parts are empty. The equal part is never empty: it starts with one item, line L6 shifts it one place to the right, line L7 does not change it, and line L8 makes it longer. So in line L6, and is an equal item; the swap moves it to and the less item to , both pointers advance, and the three properties hold. In line L7, the item at goes to the greater part and decreases; the item that comes to is not yet tested. Line L8 extends the equal part. Each step is a swap or nothing, so the range stays a permutation.
The loop ends when , so every index of the range is in one of the three parts: less , equal , greater .
Claim. If is valid at , then THREE-WAY-RADIX-QUICKSORT ends, permutes only this range, and leaves it sorted.
Proof. By induction on . Let be the largest length of a string; a valid range with at least one string has . Consider one turn of the loop at L1 with a valid range of size .
By Fact 2, the less and greater parts each miss at least the pivot item, so they have fewer than items, and they are valid at , since they are parts of a valid range. By induction, the calls of lines L9 and L10 end and sort them. After them, the range is less part, then equal part, then greater part, each part internally as above. By Fact 1, every string of the less part is less than every string of the equal part, which is less than every string of the greater part. So the range is sorted if the equal part is sorted.
If , the strings of the equal part all end at and are equal by Fact 1, so the equal part is sorted and line L11 returns a sorted range. Otherwise, by Fact 1 the equal part is valid at , and line L12 makes it the new range. Its size is at most and its depth is , because its strings have length at least . So each turn of the loop either makes the range smaller or keeps its size and increases , and , so the loop ends after finitely many turns. Each turn leaves its outer parts sorted and in order with the equal part, which becomes the new range, so the whole range is sorted if the final range is sorted.
The loop ends either at line L11, with a sorted range, or with . Then line L13 runs insertion sort on a range that is valid at . Insertion sort with the order of the suffixes from index sorts the range, and this order agrees with lexicographic order on strings that share their first characters. So the final range is sorted, and the whole original range is sorted.
Result. The first call has the range at , which is valid, so the claim gives a sorted permutation of the input.