You know each value's home address. Now: how do you actually sort using that knowledge?
Start with [3, 5, 2, 4, 1]. Value 3 lives at index 0, but its home is index 2. Easy — swap it there. But now look at what happened:
// Before swap: [3, 5, 2, 4, 1]// After swap: [2, 5, 3, 4, 1]// Value 2 arrived at index 0. Its home is index 1.// Do we: (a) advance i to 1, or (b) stay at i=0 and handle the newcomer?This is THE question that separates O(n) cyclic sort from O(n^2) selection sort. If you advance to index 1, you abandon the newcomer at index 0 — and someone else has to deal with it later, costing redundant work. If you stay put, you handle it immediately, and whatever that swap brings in gets handled too.
Both approaches sort the array. Only one does it in a single pass. Try both options in the next screen and see which one works — and which one wastes motion.
3 to its home at index 2. Now what?After swapping value 3 to its home at index 2, should i advance to 1 or stay at 0?
Three swaps at one index, and the whole array snapped into place. That cascade wasn't luck — it was the algorithm.
Here's the complete cyclic sort, fully annotated:
while (i < nums.length) { const home = nums[i] - 1; // address formula if (nums[i] !== nums[home]) { // not home yet? [nums[i], nums[home]] = [nums[home], nums[i]]; // swap to home } else { i++; // settled — advance }}The outer loop walks through every index. But the real work happens in the inner repetition: when nums[i] isn't home, you swap it out, and whatever lands at index i gets the same treatment. That implicit inner loop IS the chain reaction you just watched. It keeps firing until the right tenant finally arrives, then i advances.
Why does staying work? Each swap permanently places exactly one element at its home index — it never moves again. The chain resolves an entire cycle of misplaced values without ever incrementing i. When the cycle closes, the value that belongs at index i is sitting there, so the else branch fires and you move on.
Think of it as clearing a traffic jam from a single intersection: you don't drive around the block redirecting each car. You stand at one spot and route each arrival until the jam dissolves.
But wait — a while loop inside a while loop. Your complexity alarm should be screaming. Is this actually fast?