Purpose: Sort integers in deterministic time in the word RAM model, beating the comparison lower bound by exploiting the bit structure of the keys (Yijie Han, 2002).
Why beating is legal
The bound applies to comparison-based sorting, where the only permitted operation on keys is <. Integer sorting in the word RAM model allows arithmetic, bit operations, and indexing on -bit words in — a strictly more powerful model, so the lower bound does not apply.
Familiar examples: counting sort is and radix sort is ; neither compares keys.
The techniques
Han’s algorithm combines several word-RAM tricks:
- Packed sorting. Fit several small keys into one machine word and sort them all with a constant number of word operations (a bitonic network implemented with masks, shifts, and one multiplication).
- Signature sorting. Replace each key by a short hash “signature” so that many keys fit in a word; sort signatures, then repair the small number of ties.
- Fusion trees (Fredman-Willard) — a -tree with branching factor , where each node compares against keys in via a “sketch and multiply” trick. Gives sorting on its own.
- Range reduction. Recursively halve the key length, which is where the comes from.
The integer sorting landscape
| Algorithm | Time | Space | Notes |
|---|---|---|---|
| Comparison sort | - | the lower bound in its model | |
| Counting sort | only for small key range | ||
| Radix sort (base ) | what you actually write | ||
| Fusion trees | Fredman-Willard 1993 | ||
| Han | deterministic | ||
| Han-Thorup | expected | randomized; current best | |
| Open | ? | still unresolved |
What is actually usable
None of these. But the ideas are:
- Radix sort genuinely beats
std::sortby 3-5× on large arrays of 32-bit integers. An LSD radix sort with 8-bit digits is 25 lines and does four counting-sort passes. Worth having in a template library for problems with . - Packing several values into one word and operating on them in parallel is the same idea as bitset optimization — a speedup that turns into something passable.
- Sorting by a cheap key first, then repairing ties is a useful general pattern (it is also how prefix doubling sorts suffixes).
Radix sort, concretely
void radixSort(vector<uint32_t>& a) {
vector<uint32_t> b(a.size());
for (int shift = 0; shift < 32; shift += 8) {
int cnt[257] = {};
for (uint32_t x : a) cnt[((x >> shift) & 255) + 1]++;
for (int i = 0; i < 256; i++) cnt[i + 1] += cnt[i];
for (uint32_t x : a) b[cnt[(x >> shift) & 255]++] = x;
swap(a, b);
}
}Variants / Use Cases
- Sorting — the topic page covering every practical sort
- Fusion trees, van Emde Boas — the other word-RAM structures
- Bitset optimization — the practical form of word-level parallelism
- Complexity Theory — models of computation and why lower bounds are model-relative