Counting Sort
Table of Contents + β
Most sorting you have seen so far works by comparing two values and asking βwhich one is bigger?β Think of bubble sort, merge sort, or quick sort. Every one of them works by comparing. The problem is that comparing has a speed limit. No matter how clever you are, comparison sorts cannot go faster than O(n log n). So here is the question. What if we never compare at all? Counting sort does exactly that. It just counts. And that lets it sort faster than the comparison limit when the numbers are small.
π― The Problem First
Say you have a list of student marks, all between 0 and 100. Thousands of students. You want them sorted.
A comparison sort will keep asking βis 85 bigger than 72?β over and over. That work piles up.
But the marks are just numbers from 0 to 100. There are only 101 possible values. So instead of comparing marks against each other, you can count how many students got each mark. That counting idea is the whole trick behind counting sort, a sorting method that puts things in order by counting how often each value appears instead of comparing values.
Note
Counting sort only works when your values are integers in a small known range, like 0 to 100 or 0 to 1000. It is not for sorting names, decimals, or huge numbers.
π§ The Idea With a Real Example
Imagine a teacher collecting quiz scores. The scores can only be 0, 1, 2, 3, 4, or 5.
The teacher does not line up papers and compare them. She just makes a tally. Five students got a 2, three students got a 4, and so on. Then she reads the tally back in order. All the 0s first, then the 1s, then the 2s. The papers come out sorted.
That tally is the count array, a small array where each index stands for a possible value and stores how many times that value appeared.
Let us sort this list: [2, 5, 3, 0, 2, 3, 0, 3]. The values go from 0 to 5.
First we count each value.
See the count array [2, 0, 2, 3, 0, 1]? It reads like this:
- value 0 appeared 2 times
- value 1 appeared 0 times
- value 2 appeared 2 times
- value 3 appeared 3 times
- value 4 appeared 0 times
- value 5 appeared 1 time
Now the rebuild step. We walk the count array from the smallest value to the largest. For each value, we write it out as many times as the count says. So we write two 0s, skip 1, write two 2s, write three 3s, skip 4, and write one 5. That gives [0, 0, 2, 2, 3, 3, 3, 5]. The list is fully sorted, and we never compared two numbers even once.
πͺ Steps to Do Counting Sort
Here is the plan before we write any code.
- Find the largest value in the input. Call it
max. This tells us how big the count array must be. - Make a count array of size
max + 1, filled with zeros. The+ 1is because we need a slot for 0 too. - Walk through the input. For every value
v, docount[v] = count[v] + 1. Now each slot holds how many times that value appeared. - Rebuild the sorted list. Walk the count array from index 0 upward. For each index
i, write the valueiinto the outputcount[i]times. - The output is now sorted.
Tip
The largest value decides the size of the count array. If your biggest number is 100, you need 101 slots. If it is one million, you need a million slots. That is why counting sort is only a good idea when the range is small.
π» Counting Sort in Code
Below is a clean counting sort. We write a function that takes the array, counts the values, then rebuilds the array in sorted order. The same array is filled back in place.
# Sort a list of small non-negative integers by counting.def counting_sort(arr): # Step 1: find the largest value. max_val = max(arr)
# Step 2: count array of size max_val + 1, all zeros. count = [0] * (max_val + 1)
# Step 3: count how many times each value appears. for v in arr: count[v] += 1
# Step 4: rebuild the list in sorted order. pos = 0 for value in range(max_val + 1): while count[value] > 0: arr[pos] = value pos += 1 count[value] -= 1 return arr
numbers = [2, 5, 3, 0, 2, 3, 0, 3]print(counting_sort(numbers))The output of the above code will be:
[0, 0, 2, 2, 3, 3, 3, 5]Tip
Read the rebuild loop slowly. The outer loop walks every possible value from 0 to max. The inner while writes that value as many times as it was counted. When a value never appeared, its count is 0. So the inner loop runs zero times and we skip it. That is why missing values like 1 and 4 just disappear from the output.
β±οΈ How Fast Is It?
Let n be how many items you are sorting. Let k be the size of the value range, which is max + 1.
We do two walks. One walk over the n input items to count them. One walk over the k count slots to rebuild. So the total work is the two walks added together.
Note
Counting sort runs in O(n + k) time and uses O(n + k) space. The k comes from the count array. When k is small compared to n, this is basically linear time, which is faster than the O(n log n) limit that comparison sorts cannot beat.
This is the special part. Counting sort is non-comparison, meaning it never asks βis a bigger than b?β Because it skips comparing, it is not bound by the O(n log n) speed limit that applies to every comparison sort. For small-range integers, it just walks past that barrier.
But watch the k. Say you try to sort the values [1, 1000000]. Now k is a million even though n is only 2. The count array would have a million slots for two numbers. That is wasteful and slow. So big ranges kill counting sort.
Here is the full picture.
| Case | Time | Space |
|---|---|---|
| Best case | O(n + k) | O(n + k) |
| Average case | O(n + k) | O(n + k) |
| Worst case | O(n + k) | O(n + k) |
Notice the time is the same in every case. Counting sort does not care if the input is already sorted or fully shuffled. It always does the same two walks.
β οΈ Common Mistakes
A few things trip people up. Watch out for these.
- Making the count array size
maxinstead ofmax + 1. You need a slot for the valuemaxitself, so the size must bemax + 1. Off by one here crashes the program. - Forgetting that plain counting sort assumes non-negative integers. If your data has negative numbers, you must shift every value by the minimum first, or the index goes negative.
- Using it on a huge range. If values go up to a million but you only have ten items, the count array wastes a million slots. Pick a different sort then.
- Trying to sort decimals or text with it. The value has to be a whole number you can use as an array index. Counting sort cannot index by 3.5 or by βappleβ.
π§© What Youβve Learned
- β Counting sort sorts by counting how often each value appears, not by comparing values.
- β The count array has one slot per possible value, and each slot holds that valueβs frequency.
- β The rebuild step walks the count array and writes each value as many times as it was counted.
- β It runs in O(n + k) time and O(n + k) space, where k is the size of the value range.
- β Because it never compares, it beats the O(n log n) limit for small-range integers, but a large range makes it slow and wasteful.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does counting sort use instead of comparing values?
Why: Counting sort tallies the frequency of each value in a count array, then rebuilds the list from those counts.
- 2
If the largest value in the input is max, what size must the count array be?
Why: You need a slot for every value from 0 up to and including max, which is max + 1 slots.
- 3
What is the time complexity of counting sort, where k is the value range?
Why: It walks the n input items to count them and the k count slots to rebuild, giving O(n + k).
- 4
When is counting sort a poor choice?
Why: A large range means a huge count array, wasting time and memory even for few items.