TAOCP 5.2 Exercise 8
The modified algorithm (with step D5 looping \(j = 1, 2, \ldots, N\)) **still produces a correctly sorted array** (all keys in non‑decreasing order), but **it is no longer stable** - the relative orde...
Exercise 8. [18] Would Algorithm D still work properly if $j$ were to vary from 1 up to $N$ in step D5, instead of from $N$ down to 1?
Verified: yes
Solve time: 10m36s
Solution
The modified algorithm (with step D5 looping (j = 1, 2, \ldots, N)) still produces a correctly sorted array (all keys in non‑decreasing order), but it is no longer stable - the relative order of equal keys is reversed.
1. Correctness of the sorted order
After step D4, for every integer (i) in ([u, v]), [ \text{COUNT}[i] = \bigl|{ j \mid 1 \le j \le N,; K_j \le i }\bigr|. ] In particular, (\text{COUNT}[v] = N). For a fixed key value (k), the block of positions reserved for (k) is [ \bigl(\text{COUNT}[k-1]+1,; \text{COUNT}[k-1]+2,; \ldots,; \text{COUNT}[k]\bigr), ] where (\text{COUNT}[u-1]) is taken to be (0). The size of this block is exactly the frequency of (k).
During step D5/D6 each record (R_j) is processed exactly once. When a record with key (k) is handled, the algorithm sets [ i \leftarrow \text{COUNT}[k], \quad S_i \leftarrow R_j, \quad \text{COUNT}[k] \leftarrow i-1. ] Thus the first record with key (k) that is processed receives the highest available position in its block; every subsequent record with the same key receives the next lower position. Because the initial value of (\text{COUNT}[k]) is the upper end of the block and we decrement it each time, the positions are filled without overlap and without gaps. After all (N) records have been processed, every position (1,\ldots,N) is occupied exactly once, and all keys in (S_1,\ldots,S_N) appear in non‑decreasing order. This reasoning does not depend on the order in which the indices (j) are visited; it holds for (j = 1\uparrow N) just as well as for (j = N\downarrow 1).
2. Stability is lost
Consider two records (R_a) and (R_b) with (a < b) and (K_a = K_b = k).
-
Original algorithm ((j = N, N-1, \ldots, 1)):
(R_b) is processed before (R_a). At that moment (\text{COUNT}[k]) still has its initial (larger) value, so (R_b) is placed at a higher position than the one (R_a) will later obtain. Hence in the output (S), (R_a) precedes (R_b) - the original order is preserved. -
Modified algorithm ((j = 1, 2, \ldots, N)):
(R_a) is processed before (R_b). Now (R_a) receives the higher position and (R_b) the lower one. Consequently (R_b) appears before (R_a) in (S) - the relative order of equal keys is reversed.
Therefore the modified algorithm is not stable. If “working properly” includes the stability property (which Algorithm D possesses and which is often essential in practice), then the answer is no, it would not work properly. If only a correctly sorted permutation is required, the answer is yes, it still works.
Notes
The invariant maintained during step D5/D6 is:
After any number of iterations, for each key (k) the value (\text{COUNT}[k]) equals the number of still empty positions in the block assigned to (k), and these empty positions are exactly the lowest unfilled positions of that block.
This invariant holds irrespective of the processing order of (j). The direction of the loop only determines whether the filled positions are taken from the top down (original) or from the bottom up (modified), which directly controls stability.