Algorithms to Live By · ch.3 · sorting
🔤 Chapter 3 · Making order

Sorting:
the cost of order

Sorting is what you pay up front so that finding is cheap later. The punchline of this chapter is that most of the time it isn't worth paying — so err on the side of mess.

Every sort is a loan. You do a pile of work now, and the payments come back later, a little at a time, every time you look something up. Most chapters of this book are about making a better decision. This one is mostly about talking you out of the work.

The maths is old and settled — sorting is the most thoroughly studied problem in computer science. The interesting part is the bill.

1The bookshelf problem

You alphabetise your bookshelf on a Sunday. It takes an hour. Afterwards, finding any book takes about three seconds — you walk to roughly the right letter and you're there. Before, it took maybe twenty seconds of scanning. Beautiful. You've made your life better.

Have you? Run the numbers. You spent 3,600 seconds. You save about 17 seconds per lookup. You'd need to fetch a book 212 times before that Sunday breaks even — and that's ignoring the fact that the shelf drifts out of order the moment you put anything back in the wrong slot.

That is the entire chapter in one image. Sorting is an investment; searching is the payoff. The work is real, immediate, and paid by you. The benefit is small, deferred, and only collected if you actually come back. So the question isn't "what's the best way to sort?" — that one's been answered. The question is does the investment pay?

📚
Notice the asymmetry that makes this whole thing tick: sorting gets disproportionately worse as the pile grows; searching barely notices. Doubling your shelf more than doubles the sorting work — but only adds one step to a well-run search. Big piles punish the tidy far more than they punish the messy.

2How much worse does it get when the pile doubles?

That's the only question that matters when you're comparing ways of doing work. Not "how many seconds does it take" — seconds depend on your laptop, your mood, and whether the books are heavy. The durable question is about scaling: I hand you twice as much stuff, how much more work is that?

There are only a handful of answers you ever meet in the wild.

  • It doesn't care. Twice the pile, same work. Grabbing the top book off a stack takes one motion whether the stack is 10 books or 10,000. Programmers write this O(1)constant.
  • Twice the work. Twice the pile, twice the effort. Checking every book for coffee stains, scanning a list top to bottom. Fair, honest, proportional. That's O(n)linear.
  • Four times the work. Twice the pile, quadruple the effort — because every item has to be measured against every other item. This is the killer. Ten times the books is a hundred times the work. That's O(n²)quadratic, and it is where good afternoons go to die.
  • A little worse than twice. Twice the pile, slightly more than twice the work — and the "slightly" grows so gently you barely feel it. This is the best any general-purpose sort can do, and it is very close to free. O(n log n)linearithmic.

Now the name: this shorthand is Big-O notation. It deliberately throws away constants and small terms and keeps only the shape of the curve, because when n gets big, the shape is the only thing left standing. A quadratic algorithm with a brilliant implementation still loses to a linearithmic one with a sloppy one — you just have to wait long enough.

⚠️
Big-O is a worst-case promise, and it's a promise about growth, not about speed. O(n log n) beating O(n²) tells you nothing about which is faster on 12 items — for small n, the "bad" algorithm often wins, which is exactly why real sorting libraries fall back to insertion sort on tiny chunks. Big-O tells you who wins the argument eventually, not who wins today.

3The sort you'd invent yourself

Hand someone a shelf of out-of-order books and they'll find the first pair that's wrong, swap it, and carry on. Reach the end, start again. Keep going until a whole pass produces no swaps. Done — guaranteed, because every pass drags the biggest remaining book to its rightful end, like a bubble rising. That's bubble sort, and its main virtue is that you don't have to be taught it.

Its main vice is the bill. Each pass walks the whole shelf, and you need roughly as many passes as there are books. Books × passes = . A hundred books is on the order of ten thousand comparisons. A thousand books is a million. Double the shelf and you have quadrupled your Sunday.

It gets taught because it's honest about what sorting is — repeated comparison and repeated repair — and because it's three lines long. It never ships, because those three lines are quadratic and there is no amount of clever coding that fixes a curve.

4The sort you actually do

Watch someone tidy a hand of cards and you won't see bubble sort. You'll see this: pick up the cards one at a time, and slide each new one into the right place among the ones you're already holding. The left side of your hand is always sorted; the right side is the pile you haven't got to yet. That's insertion sort, and nobody had to teach you that either.

On paper it's still quadratic — sliding a card into a sorted hand can mean shifting everything, and you do that n times. But it's a much nicer quadratic. Bubble sort re-compares pairs it has already compared, over and over. Insertion sort touches each card once and then only walks as far left as it needs to. Same curve, far better constants.

And it has one genuinely magic property: on nearly-sorted input it's basically linear. If every card is already close to where it belongs, each insertion walks left by a step or two and stops. This is why it survives in production — real sorting libraries (Java's, Python's, V8's) hand small or nearly-ordered chunks to insertion sort on purpose. It's the algorithm that rewards a shelf that's almost tidy, which is the only kind of shelf anyone actually has.

🃏
Insertion sort is the one time in this book where your instinct and the optimal engineering answer are the same thing. When you fan out a hand of cards and start shuffling them left, you are running the algorithm that a highly-tuned standard library runs on the same input size. Enjoy it — it doesn't happen again.

5Divide, and it stops hurting

Here's the trick that breaks the quadratic. Instead of sorting the shelf, cut it in half. Sort each half — somehow, don't worry yet — and then merge the two sorted halves by repeatedly taking whichever of the two front books comes first alphabetically. Merging two sorted piles is cheap: one pass, one comparison per book, no backtracking. And the "somehow" resolves itself, because each half is sorted the same way: cut it in half, sort the halves, merge. All the way down to piles of one, which are already sorted for free.

That's mergesort. Count the bill: it takes log₂ n halvings to get down to singletons, and each level of the recursion does one linear pass of merging. Levels × pass = n log n. For a thousand books, bubble sort wants a million comparisons and mergesort wants about ten thousand. That's not a tune-up. That's a different universe.

The recursion, drawn Split log n times · merge once per level
1 3 4 5 6 7 8 9 3 5 7 9 1 4 6 8 5 7 3 9 1 6 4 8 7 5 3 9 6 1 8 4 merge ↑ merge ↑ merge ↑ split ↓ n n n n work per level: log₂ 8 = 3 levels × n work per level = n log n

The idea is older than most of the machines that run it. John von Neumann wrote mergesort down in 1945 — it's one of the first non-trivial programs ever written for a stored-program computer, and it was designed partly to prove that the things were worth building. It has never been beaten on the thing it's good at: it's stable, it's predictable (n log n on every input, no bad days), and it merges from tape, disk or network as happily as from memory.

And it earns its keep in the real world in a way that predates the computer. The 1890 US census had gotten so big that the 1880 count had taken most of a decade to tabulate — the census was in genuine danger of taking longer than the ten years between censuses, which would have been the end of it. Herman Hollerith's punch-card machines did the counting, and the sorting-and-merging of card decks did the ordering. It worked, the census got counted, and Hollerith's company went on to become IBM. Merging decks is still what a database does when your table won't fit in RAM.

Interactive · watch the counters Drag n up and see which number explodes
24
Bubble sort · press Play.
Comparisons
0
Swaps / writes
0
n² / 2 would be
n log₂ n would be
Exact comparison counts for all three algorithms on this shuffle — computed, not estimated. Bubble's count is always n(n−1)/2; it never gets a good day.
📈
Push n from 8 to 64 and watch the bubble row: 28 comparisons becomes 2,016. Merge goes from about 17 to about 300. That's the gap between an algorithm that gets worse in proportion to the pile and one that gets worse in proportion to the pile squared — and 64 items is still a small shelf. Now try Nearly sorted and watch insertion sort collapse to almost nothing while bubble sort does the exact same amount of work it always does.

6Sorting less

Suppose you don't need the shelf perfect. You just need to be able to find things. Then don't sort — bucket. Throw every book into a bin by its first letter: A–C here, D–F there, and so on. Twenty-six passes-worth of thinking becomes one pass, and you've gone from "one enormous search" to "one tiny search" without ordering anything. Inside each bin it's chaos, and inside each bin, chaos is fine — because a bin only holds a few dozen books and scanning a few dozen books is nothing.

This isn't a hack, it's a principle. Exact order is expensive and rarely necessary. Bucketing gets you most of the benefit of sorting for a fraction of the price, because most of what you wanted from "sorted" was just "not having to look at everything." (And if your buckets are even, you can bucket again inside them, and again — which is roughly what a database index is doing on your behalf.)

"Err on the side of messiness."

Searching an unsorted pile is O(n) — you look at everything. That sounds bad until you notice you only pay it when you actually look. Sorting is a cost you pay whether or not you ever come back. A pile charges you per use; a sorted shelf charges you a large fee up front and then a subscription forever, because every new book has to be inserted in its place and every misfiled book quietly corrupts the whole promise.

Interactive · drag both handles n = how much stuff · k = how often you'll look
🤔Drag the handles.
Sort-then-search = n·log₂n (the sort) + k·log₂n (k binary searches). Just-look = k·n (k linear scans). Units are "comparisons", which is the only currency both sides are paid in.
🧮
Drag k down to 1 and the verdict never wavers: if you're going to look exactly once, sorting is strictly a waste — you did n log n comparisons to avoid doing n. Sorting only ever pays when the searching is done many times, which brings us to the uncomfortable question of who is doing all that searching.

7Sorting is for someone else's benefit

The Los Angeles Public Library's Preston Sort Center handles millions of items a year, and the sorting there is industrial: conveyors, chutes, staff whose whole job is order. It is absolutely, obviously worth it. Why? Because the maths from the last section flips completely when k is enormous. One sort, millions of searches, by millions of people. The investment is paid once and the dividend is collected by the entire city.

Now look at your inbox. One sort — yours. One searcher — also you. k is small. And, crucially, your inbox has a search bar. Search collapses the cost of finding things in a pile from "look at everything" to "type three words", which means the payoff side of the investment has already been handed to you for free. Sorting your email into folders is paying the sorting cost to buy something you already own.

So: don't file, pile. The rule generalises cleanly. Sort when many people will search many times, and the sort is done once. Don't sort when you're the only user, the searches are rare, or a machine will do the finding for you. Libraries sort. Warehouses sort. Databases sort. You, at your desk, on a Sunday, should mostly not.

🔎
This is why the "inbox zero, folders for everything" ritual feels virtuous and delivers so little. You are doing a librarian's work for a readership of one — and the reader has a search bar. Foreshadowing Chapter 4: the pile isn't just acceptable, it's clever. Stuff you touched recently ends up on top, which turns out to be very close to the best caching strategy known.

8Sorting is fighting

Here's where it stops being about books. A comparison doesn't have to be cheap. In a sports league, a "comparison" is a match — ninety minutes, two squads, a stadium. In a flock of chickens, a comparison is a fight, paid for in blood. Once your comparison costs something real, the Big-O of your sorting algorithm stops being a performance question and becomes an ethical one.

Look at a knockout bracket with fresh eyes. Sixty-four teams, sixty-three matches, one champion — and the champion really is (probably) the best, because they beat everyone put in front of them. But ask who's second best and the bracket has nothing to say. The runner-up is just "whoever else made it to the last match", and the genuinely second-best team may have been knocked out in round one by meeting the champion early. A single-elimination bracket is a sorting algorithm that reliably computes exactly one thing: the maximum. It costs a mere n − 1 comparisons, and it buys you exactly one trustworthy number.

Want an actual ranking? Play everyone against everyone — a round robin. That's n(n−1)/2 matches: quadratic, and this is precisely why leagues are exhausting and take a whole season. A 20-team league is 190 fixtures. Double it to 40 teams and it's 780. Nobody has that many Saturdays.

Interactive · what a ranking costs in fights Hidden true strengths · upsets happen
16
Fights needed
Champion is truly #1
Runner-up is truly #2
Avg. place error
Accuracy figures are Monte Carlo over 600 fresh fields. A fight is decided by true strength plus noise, so the better player usually — not always — wins.
📊
Flip between the three formats at 16 players and read the tiles. The bracket and the round robin find the true champion about equally often — but the bracket does it in 15 fights and the round robin needs 120. Look one row down, though: the bracket names the true #2 only about a third of the time against the round robin's half, and its average placing is off by roughly three positions against the round robin's well under one. That's the deal in a single screen. A bracket is an eight-times-cheaper sort that only trusts its top result. Elo lands where you'd hope: a third of the fights, and a full ranking twice as accurate as the bracket's.

Nature ran into the same bill and found the same answers. A pecking order is a sorting algorithm implemented with beaks: birds fight pairwise until a stable ordering emerges, and thereafter the hierarchy is maintained almost without violence — a glance is enough, because the comparison has already been made and cached. The bloodshed is the sorting cost, paid up front. The peace afterwards is the dividend. Dominance hierarchies look brutal and are, in aggregate, violence-reduction machines: they are sorts that stay sorted so that nobody has to re-run the comparison.

And then there's the human trick, which is genuinely clever: stop comparing everyone to everyone, and instead give each player a number. Elo ratings (chess, and now everything from tennis to matchmaking in your video games) let you infer a full ranking from a sparse set of games, because each result updates a rating and ratings are transitive-ish. Beat someone rated far above you and your number jumps; beat someone far below and it barely moves. You get an approximate global order out of O(n)-ish games instead of O(n²). That's the same move as bucketing: give up exactness, keep almost all the value, pay a tiny fraction of the price.

🥊
Christian and Griffiths' sharpest observation in this chapter: when comparisons hurt, prefer the algorithm that does fewer of them — even if it gives a worse answer. Displacement hierarchies, rating systems and seeded brackets are all society quietly choosing a cheaper sort. The alternative isn't a better ranking. The alternative is everybody fighting everybody, forever.

9Mergesort, in a dozen lines

Mergesort is one of those algorithms that reads better in a functional language than in the language it was invented for. There's no index arithmetic and no buffer — just split, two recursive calls, and a merge that pattern-matches on which head is smaller. Flip between the two panes; they're the same program.

💡
The shape should feel familiar: split the structure, recurse on the pieces, combine the results — the same fold-shaped recursion you already write every day, just with a smarter combine step. The log n comes from the split (halving bottoms out after log n levels) and the n comes from the merge (each level touches every element once). Multiply the two and you have the entire complexity argument. Note also that merge takes the left element on ties — that one <= is what makes mergesort stable, and stability is why it's the sort your standard library reaches for.

10Check yourself

3 questions · instant feedback 0 / 3

11What's coming

We've just spent a chapter arguing that the pile on your desk is fine. The next chapter goes further and argues the pile is smart — that the reason the thing you need is usually near the top isn't luck, it's an algorithm. Once you accept you can't keep everything in order, the only question left is what to keep close and what to let go of.

🗄️
Up next · Chapter 4
Caching
Forgetting is a feature. What to keep close and what to let go — least-recently-used, why your desk is a memory hierarchy, and why a librarian and a CPU face the same problem.