3.6.1 · D2Sorting & Searching

Visual walkthrough — Bubble sort, selection sort, insertion sort — O(n²), when insertion sort wins

2,133 words10 min readBack to topic

We will build one idea at a time:

  1. What "sorted" and "out of order" even look like.
  2. What insertion sort physically does to a card.
  3. Why one slide = removing exactly one out-of-order pair.
  4. Why that makes the total work a count of out-of-order pairs.
  5. The best case, the worst case, and the average — all as pictures.

Nothing below assumes you remember any formula. If a symbol appears, it was drawn first.


Step 1 — What does "out of order" look like?

WHAT. Line up the numbers of an array as bars, left to right. If the array is sorted, the bars only ever go up as you walk rightward — like a staircase climbing. Any place where a taller bar sits to the left of a shorter bar is a spot that is "wrong".

WHY. Before we can count work, we need a precise, visible name for "wrongness". That name is the inversion.

PICTURE. Below, the pink connecting lines join every left-taller pair. A sorted array would have zero pink lines.

Figure — Bubble sort, selection sort, insertion sort — O(n²), when insertion sort wins
Recall Count the inversions in

[3, 1, 2] Pairs: (3,1) left is bigger ✓, (3,2) left is bigger ✓, (1,2) left is smaller ✗. So 2 inversions. ::: {(3,1),(3,2)} — exactly 2 pink lines.


Step 2 — What one move of insertion sort looks like

WHAT. Insertion sort keeps a sorted prefix on the left (already tidy) and an untouched suffix on the right. It picks the first untouched card, call its value , and slides it leftward, one neighbour at a time, until the card to its left is .

WHY. This is exactly how you sort a hand of playing cards: you never re-shuffle the whole hand, you just tuck each new card into the part you already hold. It is the cheapest possible way to grow an ordered list by one element.

PICTURE. The blue box is the sorted prefix; the yellow card is leaving the suffix; the arrow shows it sliding into the blue box.

Figure — Bubble sort, selection sort, insertion sort — O(n²), when insertion sort wins

Step 3 — One slide removes exactly one inversion

WHAT. Watch a single shift: a bigger neighbour on the left steps right by one slot, and our card steps left by one slot. Those two bars have just swapped their left/right order.

WHY. This is the heart of the whole page. Before the swap, that specific pair was left-taller — a pink line, an inversion. After the swap it is left-shorter — the pink line is gone. And no other pair changed its order, because only these two adjacent bars moved relative to each other.

PICTURE. The "before" has a pink crossing between the two boxed bars; the "after" has none. One shift, one pink line erased.

Figure — Bubble sort, selection sort, insertion sort — O(n²), when insertion sort wins

Step 4 — Total moves = total inversions

WHAT. Since every shift erases exactly one inversion, and the algorithm stops only when zero inversions remain, the total number of shifts must equal the number of inversions the array started with.

WHY. Think of the inversions as a jar of marbles. Each shift removes one marble. You are done when the jar is empty. So the number of shifts = the number of marbles you began with — no more, no less.

PICTURE. A running tally: each pass drains some marbles from the jar; the bar chart of "marbles removed per pass" sums to the starting inversion count.

Figure — Bubble sort, selection sort, insertion sort — O(n²), when insertion sort wins
Recall Why does this make insertion sort "adaptive"?

Its total work is glued to how messy the input actually is. A tidier input literally has fewer marbles to remove. ::: Runtime scales with , so nearly-sorted input → few inversions → little work. See Inversions and Counting.


Step 5 — The best case: already sorted →

WHAT. If the array is already sorted, there are zero pink lines. Every card we pick up finds its left neighbour is it immediately, so the stopping rule fires after one comparison and zero shifts.

WHY. We still have to look at each card once to confirm it belongs where it is — that is the "" of . But we never move anything, because there are no marbles in the jar.

PICTURE. A clean rising staircase; each card gets a single green tick ("already in place") and no arrow at all.

Figure — Bubble sort, selection sort, insertion sort — O(n²), when insertion sort wins

This is the number that beats selection sort — which the parent shows is stuck at comparisons no matter what.


Step 6 — The worst case: reverse-sorted →

WHAT. Now flip the array to a descending staircase. Here every pair is a pink line: the card at position is smaller than all cards to its left, so it must shift past every one of them.

WHY. This is the fullest possible jar of marbles. Card 1 shifts past 1, card 2 past 2, … card past . Adding these up counts every pink line in a fully-crossed picture.

PICTURE. A descending staircase with every pair joined by a pink line — a full triangular mesh. Counting the mesh lines gives .

Figure — Bubble sort, selection sort, insertion sort — O(n²), when insertion sort wins

Step 7 — The average case, and the degenerate inputs

WHAT. A random array sits between the two extremes. On average about half of all pairs are inversions, so — still , but with half the constant of the worst case.

WHY. For any two distinct values, they are equally likely to be in order or out of order in a random shuffle. So on average a random arrangement carries half the maximum number of pink lines.

Degenerate inputs — nothing breaks:

  • Empty array () ::: no cards, no comparisons, done. .
  • One element () ::: the prefix is already the whole array; the loop never runs. .
  • All equal values ::: no pair is strictly left-bigger, so → linear, and equal cards keep their order (stable).

PICTURE. A number line of "disorder" from 0 to , with the three inputs (sorted, random, reversed) marked, and the cost curve tracking it.

Figure — Bubble sort, selection sort, insertion sort — O(n²), when insertion sort wins

The one-picture summary

Everything above compressed: insertion sort is a machine that drains inversions, one adjacent shift at a time. Total moves = starting pink lines. Fewer pink lines (tidy input) → linear and it wins. Full mesh (reversed) → quadratic.

Figure — Bubble sort, selection sort, insertion sort — O(n²), when insertion sort wins
Recall Feynman retelling — the whole walkthrough in plain words

Picture the numbers as a row of bars. Anywhere a taller bar sits left of a shorter one, draw a pink string between them — that's an "out-of-order pair", an inversion. Sorting means erasing every string.

Insertion sort holds a tidy pile on the left. It grabs the next bar and slides it left. Every single slide yanks out exactly one pink string — never zero, never two. So the total number of slides it ever does equals the number of strings you started with.

If the row was already a neat staircase, there are no strings — it just glances at each bar once and finishes: that's the fast win. If the row was backwards, every pair is crossed — a full mesh of strings — so it slides the maximum times: the slow case. Real data is usually close to a staircase, so there are few strings, so insertion sort barely works and wins. That's the whole story — and it's why fast libraries like Timsort and Introsort call insertion sort on their small, nearly-tidy chunks.


#flashcards/coding

One leftward shift in insertion sort changes the inversion count by how much?
It removes exactly one inversion (one pink crossing).
Why is insertion sort's total move count exactly equal to the starting number of inversions?
Each move removes one inversion and it stops at zero inversions, so moves = starting inversions.
Best-case comparisons for insertion sort on an already-sorted array of elements?
(one confirming comparison per card, zero moves).
Maximum possible inversions in an array of distinct elements, and which input achieves it?
, achieved by a reverse-sorted array.
On a random array, roughly how many inversions are expected?
About — half the maximum, since each pair is equally likely in or out of order.