Sorting Algorithms

Counting Sort

● Intermediate ⏱ 7 min read sorting

Counting sort is a non-comparison-based sorting algorithm that sorts integers by counting occurrences. It runs in O(n+k) where k is the value range, making it faster than O(n log n) comparison sorts when k is small relative to n.

How It Works

Text
Array: [4, 2, 2, 8, 3, 3, 1]  (values 1–8, k=8)

Step 1 — Count occurrences:
  count[1]=1, count[2]=2, count[3]=2, count[4]=1, count[8]=1

Step 2 — Prefix sums (cumulative counts):
  count[i] += count[i-1]
  count[1]=1, count[2]=3, count[3]=5, count[4]=6, ..., count[8]=7

Step 3 — Place elements in output array (right-to-left for stability):
  Process 1 → output[count[1]-1] = output[0] = 1; count[1]--
  ...
  Result: [1, 2, 2, 3, 3, 4, 8]

Basic Implementation

Python
def counting_sort_basic(arr):
    if not arr:
        return arr
    max_val = max(arr)
    count   = [0] * (max_val + 1)

    for x in arr:
        count[x] += 1

    result = []
    for val, cnt in enumerate(count):
        result.extend([val] * cnt)
    return result

nums = [4, 2, 2, 8, 3, 3, 1]
print(counting_sort_basic(nums))   # [1, 2, 2, 3, 3, 4, 8]

Stable Version (Prefix Sums)

The basic version above is not stable. The stable version uses prefix sums to place each element in the output array at its exact final index, processing from right to left to preserve original order of equal elements.

Python
def counting_sort_stable(arr):
    if not arr:
        return arr
    max_val = max(arr)
    count   = [0] * (max_val + 1)

    # Step 1: count occurrences
    for x in arr:
        count[x] += 1

    # Step 2: prefix sums — count[i] now = number of elements <= i
    for i in range(1, len(count)):
        count[i] += count[i - 1]

    # Step 3: build output right-to-left (preserves stability)
    output = [0] * len(arr)
    for x in reversed(arr):
        count[x] -= 1
        output[count[x]] = x

    return output

nums = [4, 2, 2, 8, 3, 3, 1]
print(counting_sort_stable(nums))   # [1, 2, 2, 3, 3, 4, 8]
💡
Counting sort as a subroutine

Counting sort is used inside radix sort as a stable sort for individual digit positions. The stability guarantee ensures that multi-digit sorting (e.g. sort by units, then tens, then hundreds) produces the correct final order.

When to Use Counting Sort

Python
# Good: small range k, many elements n
# Sort exam scores 0–100 for 10,000 students
scores = [random_score for _ in range(10_000)]  # k=101, n=10000
# O(n+k) = O(10000+101) ≈ O(n) — much faster than O(n log n)

# Bad: large range k >> n
# Sort 10 phone numbers (10 digits each → k = 10^10)
# count array would need 10 billion slots — impractical

# The break-even point: counting sort wins when k < n log n
import math
n = 1000
k_threshold = n * math.log2(n)
print(f"Use counting sort if k < {k_threshold:.0f}")
# Use counting sort if k < 9966

Complexity Table

CaseTimeSpaceNote
All casesO(n+k)O(k)k = max value (value range)
StableYesWith prefix-sum version
Integers onlyCannot sort floats or strings directly
When k ≫ nWorse than O(n log n)Large count array dominates