Radix Sort

A non-comparison based sorting algorithm that sorts numbers digit by digit, starting from the least significant digit to the most significant digit.

Algorithm Information

Time Complexity

Best: O(d × n)
Average: O(d × n)
Worst: O(d × n)
d = number of digits, n = array size

Space Complexity

O(n + k)
k = range of digits (0-9)

Properties

• Stable sorting algorithm
• Non-comparison based
• Linear time for fixed-width integers
• Uses counting sort as subroutine
1/74
Speed: 1x

Algorithm Code

1function radixSort(arr) {
2 // Find the maximum number to know number of digits
3 const max = Math.max(...arr);
4
5 // Do counting sort for every digit
6 for (let exp = 1; Math.floor(max / exp) > 0; exp *= 10) {
7 countingSort(arr, exp);
8 }
9
10 return arr;
11}
12
13function countingSort(arr, exp) {
14 const n = arr.length;
15 const output = new Array(n);
16 const count = new Array(10).fill(0);
17
18 // Store count of occurrences of each digit
19 for (let i = 0; i < n; i++) {
20 const digit = Math.floor(arr[i] / exp) % 10;
21 count[digit]++;
22 }
23
24 // Change count[i] so it contains actual position
25 for (let i = 1; i < 10; i++) {
26 count[i] += count[i - 1];
27 }
28
29 // Build the output array
30 for (let i = n - 1; i >= 0; i--) {
31 const digit = Math.floor(arr[i] / exp) % 10;
32 output[count[digit] - 1] = arr[i];
33 count[digit]--;
34 }
35
36 // Copy the output array to arr
37 for (let i = 0; i < n; i++) {
38 arr[i] = output[i];
39 }
40}

Variable State

max:802
exp:1
digit:0
n:8
pass:1

Call Stack

radixSort

Array Visualization

Watch how Radix Sort processes each digit position from least to most significant

1700
451
752
903
24
8025
246
667

Statistics

Digit Extractions0
Element Moves0
Step1 / 74

Legend

Processing Element
Current Digit Focus
Fully Sorted
Awaiting Processing

Starting Radix Sort. Maximum number is 802, which determines the number of passes needed.

How Radix Sort Works

Discover the power of non-comparison sorting through digit-by-digit processing and bucket distribution.

Algorithm Overview

Radix Sort is a non-comparison based sorting algorithm that sorts numbers by processing individual digits. It works by distributing elements into buckets based on each digit's value, starting from the least significant digit and moving to the most significant digit.

🪣 Bucket Distribution Strategy

Unlike comparison-based algorithms, radix sort never compares elements directly. Instead, it uses the counting sort algorithm as a subroutine to sort by each digit position. This approach can achieve linear time complexity for fixed-width integers.

Step-by-Step Process

1

Find Maximum Number

Determine the maximum number in the array to know how many digits we need to process. This determines the number of passes required.

const max = Math.max(...arr);
const numDigits = Math.floor(Math.log10(max)) + 1;
2

Process Each Digit Position

Starting from the least significant digit (rightmost), use counting sort to sort the array based on the current digit position.

for (let exp = 1; Math.floor(max / exp) > 0; exp *= 10) {
  countingSort(arr, exp);
}
3

Count Digit Occurrences

For the current digit position, count how many numbers have each digit (0-9). This creates a frequency distribution.

Key Insight: We only need 10 buckets (0-9) regardless of array size!
4

Reconstruct Array

Use the counting information to place elements in their correct positions, maintaining stability by processing from right to left.


for (let i = n - 1; i >= 0; i--) {
  const digit = Math.floor(arr[i] / exp) % 10;
  output[count[digit] - 1] = arr[i];
  count[digit]--;
}

Radix Sort in Action

Here's how radix sort processes an example with 3-digit numbers:

Initial Array: [170, 45, 75, 90, 2, 802, 24, 66]
Pass 1 - Sort by Ones Digit (exp = 1):
Digits: [0, 5, 5, 0, 2, 2, 4, 6]
Buckets: 0:[170,90], 2:[2,802], 4:[24], 5:[45,75], 6:[66]
Result: [170, 90, 2, 802, 24, 45, 75, 66]
Pass 2 - Sort by Tens Digit (exp = 10):
Digits: [7, 9, 0, 0, 2, 4, 7, 6]
Buckets: 0:[2,802], 2:[24], 4:[45], 6:[66], 7:[170,75], 9:[90]
Result: [2, 802, 24, 45, 66, 170, 75, 90]
Pass 3 - Sort by Hundreds Digit (exp = 100):
Digits: [0, 8, 0, 0, 0, 1, 0, 0]
Buckets: 0:[2,24,45,66,75,90], 1:[170], 8:[802]
Result: [2, 24, 45, 66, 75, 90, 170, 802]

🔄 Stability Preservation

Radix sort maintains stability by processing elements from right to left when reconstructing the array. This ensures that elements with the same digit value maintain their relative order from previous passes.

Complete Implementation

Here's the complete radix sort implementation with counting sort subroutine:

function radixSort(arr) {
    // Find the maximum number to know number of digits
    const max = Math.max(...arr);
    
    // Do counting sort for every digit
    // exp is 10^i where i is current digit number
    for (let exp = 1; Math.floor(max / exp) > 0; exp *= 10) {
        countingSort(arr, exp);
    }
    
    return arr;
}

function countingSort(arr, exp) {
    const n = arr.length;
    const output = new Array(n); // Output array
    const count = new Array(10).fill(0); // Count array for digits 0-9
    
    // Store count of occurrences of each digit
    for (let i = 0; i < n; i++) {
        const digit = Math.floor(arr[i] / exp) % 10;
        count[digit]++;
    }
    
    // Change count[i] so that it contains actual position
    // of this digit in output[]
    for (let i = 1; i < 10; i++) {
        count[i] += count[i - 1];
    }
    
    // Build the output array
    // Process from right to left to maintain stability
    for (let i = n - 1; i >= 0; i--) {
        const digit = Math.floor(arr[i] / exp) % 10;
        output[count[digit] - 1] = arr[i];
        count[digit]--;
    }
    
    // Copy the output array to arr[], so that arr[] now
    // contains sorted numbers according to current digit
    for (let i = 0; i < n; i++) {
        arr[i] = output[i];
    }
}

// Optimized version for different bases
function radixSortBase(arr, base = 10) {
    const max = Math.max(...arr);
    
    for (let exp = 1; Math.floor(max / exp) > 0; exp *= base) {
        countingSortBase(arr, exp, base);
    }
    
    return arr;
}

function countingSortBase(arr, exp, base) {
    const n = arr.length;
    const output = new Array(n);
    const count = new Array(base).fill(0);
    
    // Count occurrences of each digit in given base
    for (let i = 0; i < n; i++) {
        const digit = Math.floor(arr[i] / exp) % base;
        count[digit]++;
    }
    
    // Convert counts to positions
    for (let i = 1; i < base; i++) {
        count[i] += count[i - 1];
    }
    
    // Build output array (stable)
    for (let i = n - 1; i >= 0; i--) {
        const digit = Math.floor(arr[i] / exp) % base;
        output[count[digit] - 1] = arr[i];
        count[digit]--;
    }
    
    // Copy back to original array
    for (let i = 0; i < n; i++) {
        arr[i] = output[i];
    }
}

// Example usage:
const numbers = [170, 45, 75, 90, 2, 802, 24, 66];
console.log("Original:", numbers);
radixSort(numbers);
console.log("Sorted:", numbers);

Key Concepts & Characteristics

✅ Advantages

  • Linear time complexity: O(d×n) where d is number of digits
  • Stable sorting: Maintains relative order of equal elements
  • Non-comparison based: Doesn't rely on element comparisons
  • Predictable performance: Consistent behavior regardless of input order
  • Parallelizable: Digit processing can be parallelized

❌ Disadvantages

  • Limited to integers: Only works with fixed-width integer keys
  • Extra memory: Requires O(n + k) additional space
  • Digit dependency: Performance depends on number of digits
  • Cache performance: Non-sequential memory access patterns
  • Not general-purpose: Cannot sort arbitrary comparable objects

🚀 Linear Time Achievement

Radix sort achieves linear time complexity by avoiding comparisons entirely. For fixed-width integers (constant d), it runs in O(n) time, breaking the O(n log n) lower bound that applies to comparison-based sorting algorithms.

Complexity Analysis

Best Case

O(d × n)

Linear time when d (number of digits) is constant or small relative to n.

Average Case

O(d × n)

Consistent performance regardless of input distribution.

Worst Case

O(d × n)

Even worst-case input maintains linear time complexity.

Detailed Analysis

Time per Pass: O(n + k) where k is range of digits (10 for decimal)
Number of Passes: d = ⌊log₁₀(max)⌋ + 1
Total Time: O(d × (n + k)) = O(d × n) when k is constant
Comparison with O(n log n): Faster when d < log n
Space Complexity: O(n + k) - Output array + counting array

Variants and Optimizations

Algorithm Variants

  • LSD Radix Sort: Least Significant Digit first (most common)
    Processes digits from right to left, suitable for fixed-width integers
  • MSD Radix Sort: Most Significant Digit first
    Processes digits from left to right, can stop early for strings
  • Binary Radix Sort: Uses base-2 instead of base-10
    More cache-friendly, processes one bit at a time

Performance Optimizations

  • Variable Base: Use larger bases (e.g., 256) for fewer passes
    Trades memory for speed, reduces number of passes
  • Hybrid Approach: Switch to comparison sort for small subarrays
    Used in MSD radix sort when partitions become small
  • In-place Variants: Reduce space complexity
    More complex but uses less memory

When to Use Radix Sort

✅ Perfect for:

  • Integer sorting: Fixed-width integers, IDs, timestamps
  • Large datasets: When n is much larger than d (number of digits)
  • Stable sorting required: Maintains relative order of equal elements
  • String sorting: Fixed-length strings (MSD variant)
  • Counting applications: When you need to count occurrences
  • Parallel processing: Easy to parallelize digit processing

❌ Avoid for:

  • Floating-point numbers: Requires special handling
  • Variable-length data: Strings of different lengths
  • Memory-constrained systems: Requires O(n + k) extra space
  • Small datasets: Overhead may not be worth it
  • Many digits: When d approaches or exceeds log n
  • General objects: Cannot sort arbitrary comparable objects

🎯 Sweet Spot

Radix sort excels when sorting large arrays of integers where the number of digits is small relative to the array size. For example, sorting millions of 32-bit integers (d=10) is much faster with radix sort than comparison-based algorithms.

Real-World Applications

Common Use Cases

  • Database indexing: Sorting large tables by integer keys
  • IP address sorting: Network routing and analysis
  • Timestamp sorting: Log file processing and analysis
  • ID sorting: User IDs, product codes, transaction IDs
  • Suffix arrays: String processing and pattern matching
  • Bucket sort implementation: As a subroutine for distribution

Industry Examples

  • MapReduce: Distributed sorting of large datasets
  • Graphics processing: Sorting pixels by color values
  • Financial systems: Transaction processing by timestamp
  • Telecommunications: Call record sorting by phone numbers
  • Scientific computing: Particle simulation data sorting
  • Web analytics: Sorting page views by visitor ID

💡 Historical Note

Radix sort is one of the oldest sorting algorithms, originally developed for use withpunch card machines in the early 20th century. The mechanical card sorters would literally sort cards into buckets based on the holes punched in each column, processing one column at a time - exactly like modern radix sort!