Algorithm Search⌘K

Proofs: Counting sort

These are the human proofs of Counting sort, at full length.

Counting sort sorts the items and keeps equal keys in input order full

This proof shows: correctness, stability.

Write κ(j)=key(A[j])\kappa(j) = \mathrm{key}(A[j]) for 0≤j<n0 \le j < n, and assume that 0≤κ(j)<k0 \le \kappa(j) < k for each jj. For a key value vv let Nv=∣{j:κ(j)=v}∣N_v = |\{j : \kappa(j) = v\}| and let Sv=∑u<vNuS_v = \sum_{u < v} N_u, the number of items with a key less than vv. Block vv is the index range [Sv,Sv+Nv)[S_v, S_v + N_v) of BB. The blocks for v=0,…,k−1v = 0, \ldots, k-1 are disjoint, they follow each other in order of vv, and together they cover [0,n)[0, n), because Sv+1=Sv+NvS_{v+1} = S_v + N_v and Sk=nS_k = n.

Step 1 (pass 1). At the test of line L2 with index ii, C[v]=∣{j<i:κ(j)=v}∣C[v] = |\{j < i : \kappa(j) = v\}| for each vv. This holds for i=0i = 0 by line L1. Line L3 adds 1 to exactly the entry v=κ(i)v = \kappa(i), so it holds for i+1i + 1. When the loop stops, i=ni = n and C[v]=NvC[v] = N_v.

Step 2 (pass 2). At the test of line L5 with index vv, we claim that s=Svs = S_v, that C[u]=SuC[u] = S_u for u<vu < v, and that C[u]=NuC[u] = N_u for u≥vu \ge v. For v=0v = 0 this holds by line L4 and Step 1, since S0=0S_0 = 0. Line L6 saves t=Nvt = N_v, sets C[v]=s=SvC[v] = s = S_v, and sets s=Sv+Nv=Sv+1s = S_v + N_v = S_{v+1}. So the claim holds for v+1v + 1. At the end, C[v]=SvC[v] = S_v for each vv.

Step 3 (pass 3). Let Pv(i)=(j1<j2<⋯<jm)P_v(i) = (j_1 < j_2 < \cdots < j_m) be the indices j<ij < i with κ(j)=v\kappa(j) = v, in increasing order. The invariant at the test of line L8 with index ii is:

(P) For each vv, C[v]=Sv+∣Pv(i)∣C[v] = S_v + |P_v(i)|, and B[Sv+r−1]=A[jr]B[S_v + r - 1] = A[j_r] for r=1,…,∣Pv(i)∣r = 1, \ldots, |P_v(i)|.

For i=0i = 0 each Pv(0)P_v(0) is empty and C[v]=SvC[v] = S_v by Step 2, so (P) holds. Assume (P) at index ii, and let v=κ(i)v = \kappa(i). Then Pv(i+1)P_v(i+1) is Pv(i)P_v(i) followed by ii. Line L9 writes A[i]A[i] at index C[v]=Sv+∣Pv(i)∣C[v] = S_v + |P_v(i)|. This index is in block vv, because ∣Pv(i)∣<Nv|P_v(i)| < N_v: the item ii itself has key vv and is not in Pv(i)P_v(i). So the write does not touch the slots of another block, and it does not touch the earlier slots of block vv. Line L10 adds 1 to C[v]C[v]. The lists and counters of all other keys do not change. So (P) holds at index i+1i + 1.

Step 4 (the result). When the loop stops, i=ni = n, and (P) says that block vv holds the NvN_v items with key vv, in increasing order of their input index, for each vv. The blocks cover BB and are in order of vv. So each slot of BB is written exactly once, BB holds each item of AA exactly once, the keys in BB are non-decreasing, and items with equal keys appear in their input order. ■\blacksquare

Termination. Each of the three loops has a fixed range of nn or kk steps, and each step does a fixed number of operations.

Back to Counting sort