Skip to content

Stable Counting Sort

Stable variant of counting sort using prefix sums to preserve relative order of equal keys.

Stable counting sort extends counting sort by preserving the relative order of equal elements. This property is required in multi-pass algorithms such as radix sort.

The algorithm uses prefix sums to compute exact output positions for each element.

Problem

Given an array AA of nn elements with integer keys in range [0,k][0, k], produce a sorted array while preserving the relative order of elements with equal keys.

Idea

Count occurrences, convert counts into cumulative positions, then place elements into the correct position from right to left.

Let:

  • C[i]C[i] store the number of elements i\le i
  • This gives the final position of each key

Algorithm

stable_counting_sort(A, k):
    C = [0] * (k + 1)

    for x in A:
        C[x] += 1

    for i in range(1, k + 1):
        C[i] += C[i - 1]

    B = [0] * len(A)

    for i from length(A) - 1 down to 0:
        x = A[i]
        C[x] -= 1
        B[C[x]] = x

    return B

Example

Let:

A=[4,2,2,8,3,3,1] A = [4, 2, 2, 8, 3, 3, 1]

Counts:

valuecount
11
22
32
41
81

Prefix sums:

valueposition
11
23
35
46
87

Final sorted array:

[1,2,2,3,3,4,8] [1, 2, 2, 3, 3, 4, 8]

Stability

The reverse traversal ensures that later occurrences of equal keys are placed later in the output. This preserves the original order.

Correctness

Each element is assigned a unique position based on cumulative counts. The mapping from input to output is one-to-one and order preserving for equal keys.

Complexity

componentcost
countingO(n)O(n)
prefix sumO(k)O(k)
placementO(n)O(n)
totalO(n+k)O(n + k)

Space:

O(n+k) O(n + k)

When to Use

Use stable counting sort when:

  • stable ordering matters
  • keys lie in a small integer range
  • used as a subroutine in radix sort
  • deterministic linear time is required

Implementation (Python)

def stable_counting_sort(a, k):
    count = [0] * (k + 1)

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

    for i in range(1, k + 1):
        count[i] += count[i - 1]

    output = [0] * len(a)

    for i in range(len(a) - 1, -1, -1):
        x = a[i]
        count[x] -= 1
        output[count[x]] = x

    return output