An integer sorting algorithm that operates by counting the number of objects that have each distinct key value. It is only suitable for direct use in situations where the variation in keys is not significantly greater than the number of items.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
{
"arr": "[4, 2, 2, 8, 3, 3, 1]",
"max": 8
}Overview
Counting Sort does not compare elements at all. It counts how many times each value occurs, turns those counts into positions, and then places each element directly into its slot in the output array. That lets it beat the O(n log n) limit that applies to comparison sorts.
The version here supports negative numbers by offsetting every value by the minimum (arr[i] - min). After counting, a running total (prefix sum) turns count[v] into 'how many elements are less than or equal to v', which is exactly the 1-based position of the last v.
Walking the input from right to left while placing elements keeps equal values in their original order, which makes the algorithm stable. That stability is what Radix Sort relies on. With the default input 4, 2, 2, 8, 3, 3, 1 the range is 1..8, so the count array has eight slots.
Step by step
- Find
minandmaxand create acountarray of sizemax - min + 1. - For every element, increment
count[value - min]. - Convert
countinto prefix sums so each entry holds an end position. - Walk the input backwards; put each value at
output[count[value - min] - 1]and decrement that count. - Copy
outputback into the original array.
Complexity
| Case | Cost | Why |
|---|---|---|
| Best case | O(n + k) | k is the value range max - min + 1; every pass is linear. |
| Average case | O(n + k) | No dependence on input order. |
| Worst case | O(n + k) | Becomes impractical when k is much larger than n. |
| Extra space | O(n + k) | The count array plus the output array. |
When to use it
- Integers (or keys that map to integers) with a small range, such as ages, grades or byte values.
- As the stable per-digit pass inside Radix Sort.
- Histogram-style problems where you need the counts anyway.
Common mistakes
- Memory explodes when the range is large: sorting two values, 0 and 1,000,000,000, needs a billion counters.
- Iterating forwards in the placement loop still sorts correctly but loses stability.
- It does not work directly on floating-point or arbitrary objects without a key-to-integer mapping.
A dry run is the best way to check your understanding of Counting Sort: follow each row, predict the next one, and compare. The run below takes 69 steps in total. Steps that only re-print loop counters are left out so the decisions stand out. The Line column refers to the line numbers in the code listing above.
- Input
- 4, 2, 2, 8, 3, 3, 1
- Result
- return value = [1, 2, 2, 3, 3, 4, 8]
| Step | Line | Array | What happens |
|---|---|---|---|
| 1 | 2 | [4, 2, 2, 8, 3, 3, 1] | max = 8 |
| 56 | 18 | [1, 2, 2, 8, 3, 3, 1] | i = 0 |
| 62 | 18 | [1, 2, 2, 3, 3, 3, 1] | i = 3 |
| 66 | 18 | [1, 2, 2, 3, 3, 4, 1] | i = 5 |
| 68 | 18 | [1, 2, 2, 3, 3, 4, 8] | i = 6 |
| 69 | 20 | [1, 2, 2, 3, 3, 4, 8] | return value = [1, 2, 2, 3, 3, 4, 8] |