Memra

Sorting in linear time

◈ 6 cards

Counting sort Θ(n+k) (stable, reverse pass); radix sort Θ(d(n+k)) (LSD, needs a stable inner sort); bucket sort Θ(n) average — how they dodge the lower bound.

Beating the bound by not comparing

Last lesson: comparison sorts need . The escape is to stop comparing and exploit structure in the keys — then we sort in linear time.

Counting sort —

Assume each key is an integer in . Counting sort uses values as indices, never comparing two keys. Four phases:

  1. Zero a count array .
  2. Count: for each , increment — now = number of keys equal to .
  3. Prefix sums: — now = number of keys , i.e. the position of the last copy of value .
  4. Place (right to left): for down to , put at and decrement .

Total , which is when . It is stable — equal keys keep their input order — because phase 4 runs right-to-left: the last occurrence of a value lands in the rightmost slot for that value.

Radix sort —

To sort -digit numbers, sort by one digit at a time, least-significant first (LSD), using a stable sort (counting sort) at each pass. Stability is load-bearing: each pass must preserve the order the previous (lower) digits established. By induction, after sorting digit the numbers are correctly ordered on their least-significant digits. With constant and , radix sort is .

Bucket sort — average

Assume keys are i.i.d. uniform on . Scatter into bucket , insertion-sort each bucket, concatenate. Under the uniform assumption each bucket holds elements in expectation, giving average time (worst case if everything clusters into one bucket).

Worked example

Counting sort on with : the counts are , prefix sums make , and the right-to-left placement yields . The runnable exercises do this and a stability demo.

012345counts C202301prefix C224778keys ≤ 3After prefix sums, C[i] = how many keys are ≤ i.
C is indexed by *key value*, not by position — that is how counting sort avoids comparing. After the prefix pass, C[3] = 7 says "seven keys are ≤ 3", which is exactly the last slot a 3 may occupy.
01234567A25302303j = 7B3C[3]−1 = 6B final00223335Right-to-left placement is what makes it stable.
Placement runs right to left. A[7] = 3 takes the *last* slot reserved for 3s, so the earlier 3s land before it — equal keys keep their input order, and that stability is what radix sort depends on.
input372145903128341920by 1s920341372903145128by 10s903920128341145372by 100s128145341372903920Each pass must be stable.
One stable counting sort per digit, least-significant first. After the tens pass the numbers are correctly ordered on their last two digits; the hundreds pass then finishes the job.
NORMAL ~/memra/learn/comp-372/sorting-in-linear-time utf-8 LF