Proofs: Multikey quicksort
These are the human proofs of Multikey quicksort, at full length.
Multikey quicksort sorts strings in lexicographic order full
This proof shows: correctness, termination.
Let for and otherwise, where is less than every character.
Fact 1. Let and agree on their first characters, with and . If , then . If , then . If , then and agree on their first characters.
Proof. If , then has length and is a proper prefix of , so . If , then is the first index where they differ, and . The other two cases follow from the definition of .
A task is valid if all strings of have length at least and agree on their first characters. Call the state good if:
(G1) the ranges of the tasks on are disjoint, and each task is valid; (G2) for indices that are not in the same task, ; (G3) holds the input strings as a multiset.
Initialization. The task is valid, and there is one task, so (G1) to (G3) hold.
Maintenance. Pop . If , the task is dropped. Its range has at most one index, which was already in a different task from every other index, so (G2) already covers all its pairs. Otherwise, line L6 permutes the range, so (G3) holds, and it creates three ranges , and with , and .
- The two outer ranges hold strings of the old task, so they are valid at depth .
- If , the strings of the middle range agree on characters by Fact 1 and have length at least , so the task is valid. If , the middle range is not pushed.
- The new ranges are disjoint and inside , so (G1) holds.
- For (G2), take in that are not in the same new task. If they are in different ranges, then , and by Fact 1. If both are in the middle range and , then by Fact 1. A pair with one index outside keeps its relation from before, because the range holds the same strings: the order between outside the range and every string of the range was the same for all strings of the range, by (G2) before the pop.
Termination. Let be the largest length of a string. A valid task has strings of length at least , so for each task with at least one string. Give a task the weight , and let be the total weight of the tasks on . Pop a task with strings, and let , and be the sizes of its three ranges, with because the pivot string is in the middle range. The children have the total weight at most , so drops by at least 1. A pop of a task with at most one string does not increase . So at most pops handle a task with two or more strings. Each of them pushes at most three tasks, so there are at most pops, and the loop ends.
Result. When is empty, (G2) holds for all pairs , so is sorted, and by (G3) it holds the input strings.