Why can selection sort reorder equal-comparing records when it performs only n-1 swaps?
answer
- measure how far one swap travels
- what happens to the evicted element
- who sits between the two swapped slots
- three records are enough to break it
- the scan is careful, the placement is not
basics
~20 sEach pass ends with one long-range swap: the element at the region boundary is thrown to wherever the minimum was found, jumping over everything between. If an equal-keyed record sits in that gap, their relative order flips.
solid answer
~50 sThe swap count is low precisely because each swap is long-range, and distance is what breaks equal-key order. Take inventory rows keyed by price, arriving in order: `(5, #1), (5, #2), (2, #3)`. The first pass finds the minimum at the last slot and swaps it with slot 0, producing `(2, #3), (5, #2), (5, #1)`. Record #1 has been thrown past #2, so the arrival tiebreak is silently inverted even though nothing compared unequal. This is why "fewer swaps and simpler code" is not a licence to substitute selection sort where the previous sort preserved the order of equal keys. You can make selection sort stable by shifting the block right and inserting the minimum instead of swapping — but that costs O(n^2) data movement, which throws away the one property you picked it for.
code
pseudocode · 6 linesfor i in 0..n-2
m = i
for j in i+1..n-1
if a[j] < a[m]
m = j
swap(a[i], a[m])go deeper
Remember that selection sort's single swap per pass can move an element a long way, and that a long move can carry a record past another record with the same key.
Explain the mechanism and produce the three-record counterexample on demand: the evicted element at the boundary is thrown to the minimum's old slot, past anything in between.
Show how this surfaces in production — a secondary order silently lost, output that churns between runs — and name the fixes and their costs, including folding the tiebreak into the key.
Own the guidance: decide whether the team's comparators are required to be total, so that equal-key order is never something a future algorithm swap can quietly take away.
## Why swap count and equal-key order are the same story Selection sort's headline property is that it writes very little: one swap per pass, at most n-1 for the whole run, regardless of input. That economy comes from doing all the work with comparisons and then making a single, arbitrarily long jump. The jump is the problem. Preserving the relative order of records that compare equal — the property usually called stability — is destroyed exactly by moves that carry an element across other elements it does not compare unequal to. ## The mechanism, concretely ``` for i in 0..n-2 m = i for j in i+1..n-1 if a[j] < a[m] m = j swap(a[i], a[m]) ``` The scan is careful: with a strict `<`, `m` keeps the *first* minimum it saw, so ties during the scan are handled conservatively. That is not where order is lost. Order is lost in the final line. `swap(a[i], a[m])` does two things: it moves the minimum into place (fine) and it evicts whatever was at `a[i]` all the way out to position `m` (not fine). That evicted element has just been carried past every element between `i` and `m`, including any that compare equal to it. Trace inventory rows keyed by price, listed in arrival order: | step | array | |---|---| | start | (5, #1), (5, #2), (2, #3) | | pass i=0: minimum is (2, #3) at index 2, swap with index 0 | (2, #3), (5, #2), (5, #1) | | pass i=1: minimum of the rest is (5, #2), already at index 1 | (2, #3), (5, #2), (5, #1) | The result is correctly sorted by price. But #1 arrived before #2 and now sits after it. Nothing compared the two prices as unequal; the eviction alone did it. Three records are enough to demonstrate the defect, which makes this a good whiteboard answer — you can produce the counterexample in ten seconds. ## Why this bites in practice The damage is invisible at the point of the swap. The output is sorted by the key you asked about, every assertion on that key passes, and the corruption only shows up downstream where something depended on the secondary order — a display that showed oldest-first within a price band, a batch that processed ties by arrival, a diff that now churns because ties come out differently on every run. That last one is nasty: run-to-run instability in output ordering looks like a data problem, not a sort problem. A second trap: people assume equal keys are interchangeable. They are interchangeable only when the records are *identical*, which is rarely true — records usually carry payload beyond the sort key, and that payload is what makes the reordering observable. ## Can you fix it? Yes, and the fix is instructive because of what it costs. Replace the swap with a rotation: shift the block from `i` to `m-1` one position right, then drop the minimum into slot `i`. No element ever crosses an equal-keyed element, so relative order of ties survives. The price is that a single pass may move O(n) elements, giving O(n^2) total data movement instead of n-1 swaps. Selection sort's one genuine advantage — minimal writes — is gone, and you are left with a quadratic sort with no compensating property. So the honest framing for an interview: selection sort trades equal-key order for write economy. If you need equal-key order preserved, either keep the sort that gave it to you, or make the key total by folding the tiebreak field into the comparison so that no two records compare equal in the first place. ## The contrast with adjacent-exchange bubbling Bubble sort, if it swaps only on a strict greater-than between neighbours, never exchanges two elements that compare equal and never moves an element across a non-neighbour. Equal keys therefore cannot cross, and relative order survives. Note the fragility: change the comparison to `>=` and the same algorithm starts swapping equal neighbours, and the property is gone. It is one character. ## Common wrong answers - "Fewer swaps means less disturbance, so it is the safer substitute." The opposite: fewer, longer swaps are what disturb equal keys. - "Only adjacent swaps can break relative order." Adjacent swaps of *equal* elements break it; long-range swaps break it much more readily. - "Selecting the first minimum makes it order-preserving." The scan is conservative; the eviction is not. - "Equal keys are interchangeable, so it cannot matter." Only if the records are identical, which they usually are not.
- Give me the smallest array that demonstrates the problem.Three records keyed by the number, listed in arrival order: (5, #1), (5, #2), (2, #3). The first pass finds the minimum at the last slot and swaps it with slot 0, yielding (2, #3), (5, #2), (5, #1). The two equal keys have swapped relative order, and no comparison between them ever said they differ.
- Can selection sort be made to preserve the order of equal keys?Yes — instead of swapping, shift the block between the boundary and the minimum one slot right and insert the minimum at the boundary. Nothing crosses an equal-keyed element, so ties survive. The cost is O(n^2) element moves rather than n-1 swaps, which discards the write economy that made selection sort attractive.
- Does bubble sort have the same problem?No, provided it swaps only when the left neighbour is strictly greater. It exchanges neighbours only, and never exchanges two elements that compare equal, so equal keys never cross. The property is fragile though: relaxing the comparison to greater-or-equal makes it start swapping equal neighbours and the guarantee disappears.
- How would you avoid the issue without changing the algorithm?Make the comparison total: fold the tiebreak field into the key, so that two records with the same primary value still compare unequal by arrival order. Then no pair compares equal, and no ordering among equals can be lost regardless of which sort you use.
saying these in an interview costs you the question
- Says fewer swaps makes it a safe drop-in substitute
- Claims only adjacent exchanges can disturb relative order
- Thinks picking the first minimum preserves tie order
- Assumes equal keys are always interchangeable records
- Cannot produce a three-element counterexample