Counting Sort
Is a linear time stable sorting algorithm that works by [see page 15, counting] the number of occurrences in the input array. Assuming the values to be sorted are non-negative integers in the range \( \{ 0, \ldots, k \} \) counting sort keeps an array \( C[0 \ldots k] \) to count elements and an array \( B[1 \ldots n] \) to write the sorted array back.
Formulation
def counting_sort(arr):
k = max(arr)
out = [0 for _ in arr]
mem = [0 for _ in range(k)]
for j in range(len(arr)):
mem[arr[j]] += 1
for i in range(1, k):
mem[i] = mem[i] + mem[i - 1]
for j in reversed(range(len(arr))):
mem[arr[j]] -= 1
out[mem[arr[j]]] = arr[j]
You can see the implementation of counting sort in alg:counting_sort.
The array mem
contains the count of each element of the array. The second for loop
of the implementation turns count into a prefix-sum array. It makes it so that the
each index of count
array holds the index/position of where that index should be
placed in the sorted array.
Then we simply iterate from the end of the input array to the front, placing
values where the prefix-sum states they go (decrementing the sum along the way).
For example consider an array \( [3, 4, 3, 1] \). After the first for loop our count
array would be \( [0, 1, 0, 2, 1] \). After the prefix-sum calculation mem
would be
\( [0, 1, 1, 3, 4] \).
To build the sorted output array we iterate from the end of the input array and
then place each element where its prefix-sum count states it should be.
In this case:
- The last value is \( 1 \), \( mem[1] = 1 \) so we place a \( 1 \) at \( out[0] \) and set \( mem[1] = 0 \).
- The next element is \( 3 \), \( mem[3] = 3 \) so \( out[2] = 3 \) and \( mem[3] = 2 \).
- The next element is \( 4 \), \( mem[4] = 4 \) so \( out[3] = 4 \) and \( mem[4] = 3 \).
- The last element is \( 3 \), \( mem[3] = 2 \) so \( out[1] = 3 \) and \( mem[3] = 1 \).