Counting Sort with Negative Keys

Extend counting sort to handle negative integers by shifting keys into a nonnegative index range.

Counting Sort with Negative Keys

Counting sort normally assumes keys lie in a nonnegative range. This variant handles negative integers by shifting all values so that the minimum becomes zero, then applying standard counting sort.

Problem

Given an array $A$ of $n$ integers that may include negative values, sort the array.

Let:

$$ \min = \min(A),\quad \max = \max(A) $$

Idea

Shift every value by $-\min$ so all keys become nonnegative:

$$ x' = x - \min $$

Then apply counting sort on $x'$ in range $[0, \max - \min]$, and map back if needed.

Algorithm

counting_sort_with_negatives(A):
    lo = minimum(A)
    hi = maximum(A)
    k = hi - lo + 1

    count = [0] * k

    for x in A:
        count[x - lo] += 1

    i = 0
    for v from 0 to k - 1:
        while count[v] > 0:
            A[i] = v + lo
            i += 1
            count[v] -= 1

    return A

Example

Let:

$$ A = [-3, -1, -2, 0, 2, 1] $$

Shift:

$$ lo = -3 $$

Mapped values:

$$ [0, 2, 1, 3, 5, 4] $$

After sorting and shifting back:

$$ [-3, -2, -1, 0, 1, 2] $$

Correctness

The transformation $x' = x - \min$ is a bijection between the original values and the shifted values. It preserves order:

$$ x_1 < x_2 \iff x_1' < x_2' $$

Counting sort correctly orders the shifted values, so mapping back yields the correct sorted order of the original values.

Complexity

Let:

  • $n$ be the number of elements
  • $k = \max - \min + 1$ be the range size

Time:

$$ O(n + k) $$

Space:

$$ O(k) $$

Properties

property value
stable yes, if using stable variant
in place no
comparison based no
supports negatives yes

When to Use

Use this variant when:

  • keys include negative integers
  • the value range is small
  • linear-time sorting is desired

Avoid when the range $k$ is large compared to $n$, since memory usage becomes inefficient.

Implementation

def counting_sort_with_negatives(a):
    if not a:
        return a

    lo = min(a)
    hi = max(a)
    k = hi - lo + 1

    count = [0] * k

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

    i = 0
    for v in range(k):
        while count[v] > 0:
            a[i] = v + lo
            i += 1
            count[v] -= 1

    return a