Proofs: Spreadsort
These are the human proofs of Spreadsort, at full length.
Spreadsort sorts its input and terminates full
This proof shows: correctness, termination.
Let be the key map, with . Write for short. For a task with and the least and the greatest value of on the range, write for the number of bits of .
Fact 1. In a pass with shift , the bin does not decrease when grows. So if then .
Proof. does not decrease in . If , then , since otherwise . So and .
Fact 2. Each bin of the pass has a spread less than . If , all keys of a bin are equal.
Proof. Keys of bin have , so two of them differ by less than . For the difference is 0, so and therefore the keys are equal.
Fact 3. The bins are in range: for each key.
Proof. , so .
Invariant. (I1) The tasks on the stack have disjoint ranges. (I2) holds the input multiset. (I3) For indices that are not in the same task, .
Initialization. The stack has the one task , and each pair of indices is in it, so (I1) to (I3) hold.
Maintenance. Pop the task . The pairs with one index outside keep their relation, because the range keeps its multiset of keys.
- If , insertion sort puts the range in order, so the pairs inside the range now satisfy (I3).
- If , all keys of the range are equal, and (I3) holds inside it.
- Otherwise, line L10 counts the bins, which are valid by Fact 3, and line L11 permutes the range so that bin fills . The permutation only swaps keys, so (I2) holds. Take inside the range in different bins. The bin of is lower, so by Fact 1. If , keys in the same bin are equal by Fact 2, so (I3) holds for the whole range. If , line L13 pushes each bin with two or more keys as a task. Its range is inside , so (I1) holds, and pairs in the same bin are in the same new task, so (I3) is not claimed for them. A bin with one key has no pair inside it.
Termination. For a task, let be the number of bits of its spread , which is at most . A task pushed by line L13 comes from a pass with , since . Its spread is less than by Fact 2, so its . So along each chain of tasks, drops by at least one with each pass, and a chain has at most passes. Each pass pushes at most tasks, with disjoint ranges of at least two keys. So the tasks at each depth have disjoint ranges, there are at most of them, and the total number of pops is at most . The loop ends.
Result. When the stack is empty, (I3) holds for all pairs of indices, and (I2) says that holds the input. So is the input in non-decreasing order.