Sorting Algorithms
Radix Sort
Radix sort sorts integers digit by digit, from least significant to most significant (LSD) or vice versa (MSD). It uses a stable sort (counting sort) as a subroutine for each digit position and achieves O(nk) where k is the number of digits — effectively O(n) for fixed-width integers.
LSD vs MSD Radix Sort
Text
LSD (Least Significant Digit first):
Sort by units digit, then tens, then hundreds, ...
Simpler to implement; produces correct result because
each pass is stable (preserves order from previous pass).
MSD (Most Significant Digit first):
Sort by highest digit first, then recursively sort each bucket.
More complex; natural fit for strings and variable-length keys.
Used in string sorting (e.g. MSD radix sort for string arrays).
For integers: LSD is the standard choice.
LSD Radix Sort Implementation
Python
def counting_sort_by_digit(arr, exp):
"""Stable sort by the digit at position exp (1, 10, 100, ...)."""
n = len(arr)
output = [0] * n
count = [0] * 10 # digits 0–9
for num in arr:
digit = (num // exp) % 10
count[digit] += 1
for i in range(1, 10): # prefix sums
count[i] += count[i - 1]
for num in reversed(arr): # right-to-left for stability
digit = (num // exp) % 10
count[digit] -= 1
output[count[digit]] = num
for i in range(n):
arr[i] = output[i]
def radix_sort(arr):
if not arr:
return arr
max_val = max(arr)
exp = 1
while max_val // exp > 0:
counting_sort_by_digit(arr, exp)
exp *= 10
return arr
nums = [170, 45, 75, 90, 802, 24, 2, 66]
print(radix_sort(nums)) # [2, 24, 45, 66, 75, 90, 170, 802]
Step-by-step Trace
Text
Input: [170, 45, 75, 90, 802, 24, 2, 66]
Pass 1 — sort by units digit (exp=1):
digits: 0, 5, 5, 0, 2, 4, 2, 6
→ [170, 90, 802, 2, 24, 45, 75, 66]
Pass 2 — sort by tens digit (exp=10):
digits: 7, 9, 0, 0, 2, 4, 7, 6
→ [802, 2, 24, 45, 66, 170, 75, 90]
Pass 3 — sort by hundreds digit (exp=100):
digits: 8, 0, 0, 0, 0, 1, 0, 0
→ [2, 24, 45, 66, 75, 90, 170, 802]
Why must the per-digit sort be stable?
After sorting by units, elements with the same units digit appear in their correct relative order. When we sort by tens, elements with the same tens digit must retain the ordering from the units pass. A non-stable sort would destroy the previous pass’s work, giving a wrong result.
When to Use Radix Sort
Python
# Radix sort is O(nk) where k = number of digits
# For 32-bit integers: k=10 decimal digits (or 32 binary digits)
# So k is effectively constant → O(n) for fixed-width integers
# Best use cases:
# - Sorting large arrays of integers with bounded values
# - Sorting fixed-length strings (treat each character as a digit)
# - Situations where O(n log n) comparison sort is a bottleneck
# Not suitable for:
# - Floating-point numbers (need special handling)
# - Variable-length strings (MSD required)
# - When n is small (overhead of multiple passes outweighs O(n log n))
# Comparison with counting sort:
# Counting sort: O(n+k) where k = max VALUE (can be huge)
# Radix sort: O(n*d) where d = number of digits (typically 10–32)
# Radix sort handles larger values without blowing up space.
Complexity Table
| Case | Time | Space | Note |
|---|---|---|---|
| All cases | O(n⋅d) | O(n+b) | d = digits, b = base (10 or 2) |
| Fixed-width ints | O(n) | O(n) | d is constant (e.g. 10 for 32-bit decimals) |
| Stable | Yes | — | Requires stable per-digit sort |
| Non-comparison | — | — | Not bounded by O(n log n) lower bound |