Theory

Two algorithms in pseudocode

Counting sort

Three passes, no comparisons.

CountingSortByRating(items):
    k ← MaxRating - MinRating + 1
    count ← array of k zeroes

    // 1. Count how many times each rating occurs.
    for each it in items:
        count[it.Rating - MinRating] += 1

    // 2. Prefix sums: count[v] becomes the index ONE PAST v's last
    //    position in the output.
    for i from 1 to k-1:
        count[i] += count[i-1]

    // 3. Place them. BACKWARDS — and that is what makes it stable.
    out ← array of len(items)
    for i from len(items)-1 down to 0:
        v ← items[i].Rating - MinRating
        count[v] -= 1
        out[count[v]] ← items[i]
        moves.Hit()
    return out

Read the third pass again. There is not a single comparison between two items. The key names the position directly.

The complexity is O(n + k): n for the passes over the data, k for the prefix sums.

Why backwards

The prefix sum gives the position of the last element with that value. Going from the end, the last item lands in the last slot of its block, the one before it in the one before, and the original order survives.

Go forwards and equal items come out reversed. One change of loop direction and stability is gone. Step 6 shows that this is not a detail.

Radix sort

Counting sort needs an array of size k. For Year that is 131 — fine. But what if the key were a full int64?

Radix sort sidesteps that: it sorts one digit at a time, and for a single digit k is only 10.

RadixSortByYear(items):
    out ← copy of items
    for d from 0 to 3:                 // ones, tens, hundreds, thousands
        out ← countingPass(out, d)     // a stable counting sort
    return out

Least significant digit first. Four passes instead of one, but each with ten buckets instead of 131.

And this is where stability becomes load-bearing

When you sort by the tens digit, the ones digit is already in order. The second pass must preserve that — otherwise the first pass's work is gone.

Preserving it is exactly what a stable sort does.

In lesson 7 stability was a property. In lesson 8 it was a consequence. Here it is a correctness condition: without it, radix sort is not untidy — it is wrong.

Step 6 shows that as two numbers and one false.