cv.cm

Coding · Algorithms

Radix sort explained: how it works, code and complexity

5 min read

Short answer

Radix sort is a non-comparison sorting algorithm that sorts integers or fixed-length strings one digit (or character) at a time. The common least-significant-digit (LSD) version sorts by the last digit first, then the next, up to the most significant one, using a stable sort such as counting sort for each pass. With d digits in base b, it runs in O(d · (n + b)) time and uses O(n + b) extra space. Because each pass is stable, the final result is fully sorted and stable.

Open Sort lines

What problem radix sort solves

Counting sort is linear but needs a count array as large as the whole key range, which is impossible for 32-bit or 64-bit integers. Radix sort splits each key into small digits and runs counting sort once per digit, so each pass needs a count array of only b entries (10 for decimal digits, 256 for bytes).

It works for any key that can be broken into a fixed sequence of small symbols: non-negative integers, dates written as YYYYMMDD, fixed-length codes such as postal codes, IP addresses and fixed-width strings.

Worked example: LSD radix sort in base 10

Sort [170, 45, 75, 90, 802, 24, 2, 66]. The largest number has 3 digits, so there are 3 passes. Each pass is a stable sort by one digit: equal digits keep the order from the previous pass.

PassSort byResult
Start[170, 45, 75, 90, 802, 24, 2, 66]
1ones digit[170, 90, 802, 2, 24, 45, 75, 66]
2tens digit[802, 2, 24, 45, 66, 170, 75, 90]
3hundreds digit[2, 24, 45, 66, 75, 90, 170, 802]

After pass 2, numbers are sorted by their last two digits. In pass 3, 2, 24, 45, 66, 75 and 90 all have hundreds digit 0, and stability keeps them in the order pass 2 produced. That is why each pass must be stable.

Python implementation

def counting_pass(nums, exp, base):
    """Stable counting sort of nums by the digit at exp."""
    count = [0] * base
    for x in nums:
        count[(x // exp) % base] += 1
    for d in range(1, base):
        count[d] += count[d - 1]
    out = [0] * len(nums)
    for x in reversed(nums):
        d = (x // exp) % base
        count[d] -= 1
        out[count[d]] = x
    return out

def radix_sort(nums, base=10):
    """LSD radix sort for non-negative integers."""
    if not nums:
        return []
    exp, biggest = 1, max(nums)
    while biggest // exp > 0:
        nums = counting_pass(nums, exp, base)
        exp *= base
    return nums

print(radix_sort([170, 45, 75, 90, 802, 24, 2, 66]))
# [2, 24, 45, 66, 75, 90, 170, 802]
print(radix_sort([3, 0, 1, 0], base=256))   # [0, 0, 1, 3]

Using base 256 means each pass looks at one byte, so 32-bit integers need only 4 passes. To include negative numbers, sort the negative and non-negative values separately and join them, or offset all keys by the minimum. For fixed-length strings, use the character code at position i as the digit and go from the last position to the first.

Time and space complexity

MeasureValueReason
Time, every caseO(d · (n + b))d passes, each a counting sort over n keys and b digit values
Extra spaceO(n + b)an output buffer and a count array per pass
Passes for 32-bit keys4 in base 25632 bits ÷ 8 bits per digit
Comparisons0digits are used as array indexes

When d is a constant (fixed-width keys) and b is chosen near n or a fixed value such as 256, the time is O(n). For n keys that are all distinct, d must be at least log_b n, so radix sort does not beat O(n log n) for arbitrary-size keys; it is fast because each step is a simple array operation.

How radix sort compares with other sorts

AlgorithmBestAverageWorstExtra spaceStable
Radix sort (LSD)O(d · (n + b))O(d · (n + b))O(d · (n + b))O(n + b)Yes
Counting sortO(n + k)O(n + k)O(n + k)O(n + k)Yes
Merge sortO(n log n)O(n log n)O(n log n)O(n)Yes
QuicksortO(n log n)O(n log n)O(n²)O(log n)No
HeapsortO(n log n)O(n log n)O(n log n)O(1)No
Timsort (Python sorted)O(n)O(n log n)O(n log n)O(n)Yes

In the table, n is the number of keys, k the key range for counting sort, d the number of digits and b the base. LSD radix sort is stable as long as every digit pass is stable. It needs keys with a fixed structure, while comparison sorts such as merge sort and quicksort work with any ordering, including custom comparison functions.

LSD vs MSD, and common mistakes

LSD (least significant digit first)MSD (most significant digit first)
Order of passeslast digit to firstfirst digit to last, recursively per bucket
Best forfixed-length integers and stringsvariable-length strings, early exit on unique prefixes
Implementationsimple looprecursive; usually switches to insertion sort for small buckets
Stableyes, with a stable passyes, with stable bucket distribution

When to use radix sort

Radix sort is a good fit for large arrays of fixed-width integers or keys, such as 32-bit IDs, timestamps, IPv4 addresses or fixed-length strings, especially on GPUs and in high-performance libraries where its regular memory access pays off. It is used in suffix-array construction and in some database and graphics workloads. For ordinary Python lists, sorted() is almost always faster in practice because it runs in optimized C code. In interviews, radix sort comes up when asked how to sort in linear time, for example the Maximum Gap problem.

FAQ

Is radix sort stable?

LSD radix sort is stable when every digit pass uses a stable sort such as counting sort. The algorithm actually depends on that stability to be correct.

What is the time complexity of radix sort?

O(d · (n + b)), where d is the number of digits, n the number of keys and b the base. For fixed-width keys, d and b are constants, so it is linear in n.

Is radix sort faster than quicksort?

It can be for large arrays of fixed-width integers, because it does no comparisons and accesses memory in a regular pattern. For general data, small arrays or custom orderings, quicksort or the built-in sort is usually better.

What is the difference between LSD and MSD radix sort?

LSD sorts from the least significant digit to the most significant with one simple pass per digit. MSD starts with the most significant digit and recursively sorts each bucket, which suits variable-length strings.

Can radix sort sort strings?

Yes. Treat each character as a digit. LSD works directly for strings of equal length; MSD radix sort handles strings of different lengths.

All coding tutorials