Python Tutorial
Radix Sort
Sort integers digit by digit, from least to most significant, using a stable counting sort per digit.
Sorting by Digits
Radix sort avoids element comparisons entirely. It processes numbers one digit at a time — least-significant-digit (LSD) first — using a stable sort (usually counting sort) at each digit. After processing every digit, the array is fully sorted. For n numbers with d digits it runs in O(d · (n + b)), where b is the base (10 for decimal).
Implementation (LSD, base 10)
def counting_sort_by_digit(arr, exp):
n = len(arr)
output = [0] * n
counts = [0] * 10 # digits 0-9
for x in arr:
digit = (x // exp) % 10
counts[digit] += 1
for i in range(1, 10): # prefix sums
counts[i] += counts[i - 1]
for x in reversed(arr): # right-to-left keeps it STABLE
digit = (x // exp) % 10
counts[digit] -= 1
output[counts[digit]] = x
return output
def radix_sort(arr):
if not arr:
return arr
max_val = max(arr)
exp = 1
while max_val // exp > 0: # one pass per digit
arr = counting_sort_by_digit(arr, exp)
exp *= 10
return arr
print(radix_sort([170, 45, 75, 90, 802, 24, 2, 66]))
# [2, 24, 45, 66, 75, 90, 170, 802]Why Stability Is Essential
Radix sort only works if each digit pass preserves the order established by previous, less-significant digits. That is exactly what a stable sort guarantees. Using an unstable sort per digit would scramble the partial ordering and produce wrong results.
Trace 170 and 90: after the units pass both end in 0 and keep their order; the tens and hundreds passes then place them correctly. Stability carries the earlier work forward.
Complexity
| Metric | Value |
|---|---|
| Time | O(d · (n + b)) |
| Space | O(n + b) |
| Stable? | Yes |
| Comparisons | None |
When the number of digits d is small and fixed, radix sort is effectively O(n) — faster than comparison sorts on large sets of bounded-size integers.
Limitations
- Designed for integers or fixed-length strings, not arbitrary comparables.
- Negative numbers need special handling (sort magnitudes and reverse, or offset by the minimum).
- Very large numbers (many digits) increase
dand erode the advantage.
Best Practices
- Use radix sort for large volumes of integers or fixed-width keys.
- Always pair it with a stable per-digit sort (counting sort).
- Consider a larger base (e.g. 256) to reduce the number of passes on big data.
- For general data, comparison sorts remain the practical default.
Try It Yourself
Exercise 1: Why must the per-digit sort in radix sort be stable?
Show solution
Stability preserves the ordering established by earlier (less-significant) digit passes; an unstable sort would scramble that partial order and produce wrong results.
Exercise 2: How many digit passes does radix sort make on the number 802?
Show solution
Three — one for the units, tens, and hundreds digits.
📘 Real-World Deep Dive
Knowing <strong>DSA Radix Sort (algorithms & data structures)</strong> well is what turns algorithms & data structures from a curiosity into a daily tool — you'll reach for it in nearly every real project.
Real-Life Scenario
An end-to-end usage of DSA Radix Sort that you'd actually see in a data pipeline or analytics notebook.
Real-Life Example
def radix(xs):
if not xs: return xs
iters = max(len(str(abs(x))) for x in xs)
place = 1
for _ in range(iters):
buckets = [[] for _ in range(10)]
for x in xs:
buckets[(x // place) % 10].append(x)
xs = [v for b in buckets for v in b]
place *= 10
return xs
print(radix([170, 45, 75, 90, 802, 24, 2, 66]))Expected Output
(see source)Common mistakes
- Off-by-one errors in binary-search: the standard idiom is
while lo <= hiwithmid = (lo + hi) // 2. - Recursive algorithms blow the stack for n > ~10⁴; convert to iterative with an explicit stack.
- Comparison algorithms (
sorted(iterable)) are stable by default in Python — surprising for Java/C++ users. - Treating DSA Radix Sort as a black box without reading the docs — the API has subtle defaults that bite when you scale.
🚀 Performance & Best Practices
- Use
bisect.bisect_left/bisect_rightinstead of writing your own binary search. - Convert a sorted search into a tuple-access pattern with
numpy.searchsortedfor huge arrays. - Use
heapqfor priority queues instead of maintaining a sorted list manually. - When working with algorithms & data structures, prefer vectorised / batched operations over Python loops.
🧪 Try It Yourself
- Reproduce the snippet on a representative slice of your own data.
- Profile the snippet with
cProfileortimeitand find the single biggest improvement. - Generalise the snippet into a small, reusable function you can drop into future projects.