Counting Sort

Sorts without comparisons by counting how many of each value there are; linear time for small ranges.

Worth knowing first

#How does it work?

Counting sort never compares elements with each other. Instead it counts how many of each value there are.

Running totals of the counts tell where each value starts in the output; if 5 values are smaller than 3, the first 3 goes to slot 5. Then the elements are walked left to right and dropped straight into place.

When the value range (k) is small it runs in linear time, beating the O(n log n) lower bound of comparison sorts. It keeps equal values in order, so it is stable.

#Live animation

$ counting_sort --visualizeStep 1/19

Counting sort makes no comparisons: it counts how many of each value there are and computes everyone's place.

Comparisons: 0Moves: 0CountingPlacedSlot knownIn place
for each value v in a: count[v] = count[v] + 1
start[v] = how many values are smaller than v // prefix sums
for each value v in a (left to right):
output[start[v]] = v; start[v] = start[v] + 1
a = output

#Step by step

  1. 01Count how many of each value there are.
  2. 02Turn the counts into running totals: each value's starting slot in the output.
  3. 03Walk the array left to right; put each element at the next slot for its value.
  4. 04Advance that value's slot counter.
  5. 05Copy the output back.

#Example code

The same algorithm in 8 languages. Every program is compiled, run and checked to print the same output.

def counting_sort(a: list[int]) -> list[int]:
    """Sorts non-negative integers without comparing elements. Stable."""
    if not a:
        return a
    count = [0] * (max(a) + 1)
    for v in a:
        count[v] += 1
    # Running totals: count[v] becomes the slot just after the last v.
    for v in range(1, len(count)):
        count[v] += count[v - 1]
    output = [0] * len(a)
    # Walk from the right so equal values keep their order.
    for v in reversed(a):
        count[v] -= 1
        output[count[v]] = v
    return output


print(*counting_sort([4, 2, 2, 8, 3, 3, 1]))

#Complexity

BestO(n + k)
AverageO(n + k)
WorstO(n + k)
Extra memoryO(n + k)
Stable?Yes
In place?No

n is the number of elements and k the value range (max − min + 1). If k is small compared to n, it runs in linear time. If values span a huge range (say 1 to a billion), the count array becomes enormous and the algorithm impractical.

#When to use it?

Very fast for integers in a small range (ages, grades, pixel values 0–255). It is the helper inside each digit pass of radix sort. Not suitable for decimals or wide ranges.

#Practice

Log in to answer questions and save your progress.

Easy

1/3

How many comparisons does counting sort make?

  • 1None
  • 2n
  • 3n log n
  • 4n²

Medium

1/1

For [3, 1, 3, 2], after running totals, at which index (from 0) do the 3s start?

  • 12
  • 23
  • 31
  • 40

Hard

1/1

Why isn't counting sort bound by the O(n log n) limit?

  • 1It makes no comparisons; that bound is for comparison sorts
  • 2It uses no extra memory
  • 3It is recursive
  • 4It only works on sorted data

#Up next

Lessons that build on this one: