Skip to content

Radix sort

Sort by the last digit with a stable sort, then by the next digit, then by the first, and the numbers are sorted. O(d(n + b)) for d digits in base b.

Helps to know firstCounting sort

Helps to know first
This topic

First, the picture

Sort ten three-digit numbers by their last digit first, then by the middle one, then by the first. It seems backwards. Watch the third pass finish the job.

Sorting numbers digit by digit

Ten three-digit numbers sorted in three passes

static void sort_by_digit(int *a, int *tmp, int n, int exp){    int count[10] = { 0 };    for (int i = 0; i < n; i++)        count[(a[i] / exp) % 10]++;    for (int d = 1; d < 10; d++)        count[d] += count[d - 1];    for (int i = n - 1; i >= 0; i--) {        int d = (a[i] / exp) % 10;        count[d]--;        tmp[count[d]] = a[i];    }    for (int i = 0; i < n; i++)        a[i] = tmp[i];} int main(void){    int a[N] = { 512, 307, 845, 120, 693, 251, 718, 406, 934, 165 };    int tmp[N];    for (int exp = 1; exp <= 100; exp *= 10) {        sort_by_digit(a, tmp, N, exp);        for (int i = 0; i < N; i++)            printf("%d ", a[i]);        printf("\n");    }    return 0;

main has started: a and tmp have room for ten ints each.

pass
–
dealt
0

Output

0.00 / 34.50 s
Describe this picture

Two pictures stacked, with the code beside them, the line about to run marked. At the top, the ten cells of int a[10]: 512 307 845 120 693 251 718 406 934 165. Below, tmp drawn as ten bins, numbered 0 to 9, one per digit; each bin is the run of cells of tmp the running totals give that digit. The clip takes about 35 seconds, in three passes. In the first pass, by the units digit, the numbers are dealt from the right: the marker i starts at 165, its cell is tinted, a line over the bins reads “(165 / 1) % 10 = 5”, bin 5 lights and 165 flies into it. The cells already dealt grey. When all ten are in their bins, a takes them back in bin order: 120 251 512 693 934 845 165 406 307 718. The second pass, by the tens digit, gives 406 307 512 718 120 934 845 251 165 693. The third, by the hundreds digit, puts 120 and 165 in bin 1 in that order, and a ends sorted: 120 165 251 307 406 512 693 718 845 934. Under the picture are one sentence on the current step and the readouts “pass” and “dealt”. The transport plays and pauses, steps one beat back or forward, and scrubs; a paused step is kept in the page address as radix-sort.step.

Last digit first

Each pass is a Counting sort on one decimal digit: count the digits, take running totals, place the numbers from the right into tmp, copy back. Because counting sort places from the right, each pass is stable: numbers with the same digit keep the order they came in.

That is why the last digit goes first. After the units pass, the numbers are in order of their units. The tens pass sorts them by tens, and among numbers with the same tens digit it keeps the units order, so the numbers are now in order of their last two digits. The hundreds pass does the same for all three digits. Each pass must be stable, or it would throw away the order the earlier passes built.

The code and its cost

static void sort_by_digit(int *a, int *tmp, int n, int exp)
{
    int count[10] = { 0 };
    for (int i = 0; i < n; i++)
        count[(a[i] / exp) % 10]++;
    for (int d = 1; d < 10; d++)
        count[d] += count[d - 1];
    for (int i = n - 1; i >= 0; i--) {
        int d = (a[i] / exp) % 10;
        count[d]--;
        tmp[count[d]] = a[i];
    }
    for (int i = 0; i < n; i++)
        a[i] = tmp[i];
}

(a[i] / exp) % 10 is the digit: with exp = 1 the units, 10 the tens, 100 the hundreds. main calls sort_by_digit for exp = 1, 10 and 100, and prints a after each pass:

120 251 512 693 934 845 165 406 307 718
406 307 512 718 120 934 845 251 165 693
120 165 251 307 406 512 693 718 845 934

Look at 120 and 165 in the last pass. Both have hundreds digit 1, so the hundreds pass cannot tell them apart; it keeps them in the order the tens pass left them, where 120 (tens digit 2) came before 165 (tens digit 6).

A pass costs n steps for each of its loops over the numbers and b for each loop over the digits. With d digits in base b, the whole sort is O(d(n + b)). For a fixed number of digits that is linear in n, and no key is ever compared with another.

Bases and the other direction

The base need not be 10. Base 256 sorts unsigned 32-bit integers in 4 passes (signed ones need their sign bit flipped first, so that negatives come before positives), one byte each, with 256 counters a pass; the digit is (x >> (8 * p)) & 0xFF. A larger base means fewer passes but more counters.

The most-significant-digit variant goes the other way: deal by the first digit into bins, then sort each bin separately and recursively by the next digit. It can stop as soon as a bin holds one item, and it suits strings, whose first characters usually decide the order.

Worked example

An unstable last pass. Suppose the hundreds pass placed numbers with equal digits in any order. 120 and 165 both have hundreds digit 1, so 165 could land before 120, and the result would be wrong even though every number is in the right bin.

A million 32-bit keys. In base 256: 4 passes × (10⁶ + 256) steps ≈ 4 × 10⁶. A good comparison sort needs about n log₂ n ≈ 2 × 10⁷ comparisons.

Two checks. How many passes for six-digit numbers in base 10? (6.) In base 1,000? (2.)

Where it’s used

Large arrays of integer keys, where a few byte passes beat comparisons.

Strings of a fixed length, such as codes and dates written as digits, one character per pass from the right.

Graphics, which sorts thousands of objects by their depth every frame.

Reference card

Code or ideaMeaning
(a[i] / exp) % 10the digit for exp = 1, 10, 100, …
one passa stable counting sort by one digit
order of passesleast significant digit first
why stableties keep the order the earlier passes built
costO(d(n + b)): d digits, base b
base 25632-bit keys in 4 byte passes
MSD firstbins, then each bin recursively; suits strings

Platform: C11, gcc on x86-64 Linux: int 4 bytes, pointers 8, little-endian. Addresses in the pictures are short stand-ins, by one rule for the whole course; sizes are the real ones.

End of the lesson

Where to go next.

New lessons by email

Are you 13 or over?

Accounts and email updates are for people aged 13 or over. We keep only your answer, never your date of birth.

Phasorium

Account

Sign inWith Google, GitHub or your email

Subjects

Site

Look