◈ algorithms mapAlgorithms · Page 03/10
Algorithms from the constraint up · page 03

03All You're Allowed to Know Is Which One Is Bigger

Page 1 counted five shuffled cards and found 120 orderings. Page 2 put that count aside for a page. Now we pick it up again, and the question is the one page 1 stopped just short of: what does it cost to name which of the 120 you are holding?

Play it as twenty questions. The five cards are face down. You may ask me anything of the form is this one smaller than that one?, and I answer honestly every time. Keep asking and eventually one ordering is left standing.

Most people guess ten, or fifteen.
The answer is seven.

And it is seven in the strong sense, which is the sense this whole page turns on. Seven is not what a clever method manages. Seven is what nobody beats — not you, not me, not any procedure anyone will ever write. There is no code on this page yet and there does not need to be, because the seven falls out of counting alone. That is where a floor comes from.

01One question, and half of them are gone

Ask one question and count what survives. Is card a smaller than card b? I say yes, every ordering that put b first is dead, and 60 are still standing. Now throw that question away and open with a different one. Is c smaller than e? Again 60. That is not luck and it is not a property of the pair you happened to pick. Fix any two positions, and pair every ordering with the ordering that swaps those two values. The pairing touches each of the 120 exactly once, and it flips the answer, so the two sides have to come out equal (120 ÷ 2 = 60). Your opening question is a fair coin whatever you ask. No first question is better than any other, which is a slightly deflating thing to learn about a game you were about to try to play well.

Symmetry only ever covered question one. After it the deck is no longer fresh, and this is exactly where each comparison halves it starts telling you something false. Sixty orderings are left, all of them with a before b. Ask is c smaller than d? and you get 30 and 30, a clean halving, because c and d had nothing to do with a and b and the same swap-pairing runs again inside the 60. Ask is b smaller than c? instead and the split is 20 yes and 40 no. Answer no and you are holding 40 where 30 was on the table. Then push it until it breaks. From the 20 orderings with a before b before c, ask is a smaller than c? The answer is yes for all 20, the no branch comes out empty, and the counter does not move at all. That is a perfectly legal question that buys you literally nothing. Fig. 1 hands you the opening move and takes any prediction you want to commit, then runs these deeper rows in full. And it is that dead branch, rather than any slogan, that makes the number at the end of this section a floor rather than a running time.

an ordering ranks a b c d e 1–5 · "x<y" asks: is x's rank the smaller? THE 120, COUNTED SWAP THOSE TWO RANKS pick a pair, then commit
Pick any pair for your opening question — is x smaller than y? — then say how many of the 120 orderings survive my honest answer.
your opening question
how many of the 120 survive?
pick a pair and commit a count
what changedNothing yet. All 120 orderings of a b c d e sit on screen with none of them eliminated. Choose the pair you want to ask about.
why this readingThe convention on screen: an ordering hands each card a rank from 1 to 5, and is x<y? asks whether x drew the smaller rank. I answer honestly every time.
what it buysA number you name before the count runs — which is the only arrangement under which the count can surprise you.
Fig. 1. Pick the opening question yourself and commit what survives. Every first comparison lands on 60, whichever pair you choose, because swapping those two values pairs the 120 orderings off two by two. Then push deeper: is c<d? splits 30/30, is b<c? splits 20/40, and from a<b<c the question is a<c? leaves the counter on 20 with the no-branch drawn empty. Halving is the best a question can do, not what a question does.

So halving is not what a question does. Halving is the best a question can do, and a best case is a thing you can spend. Start at 120 and take the best split every single time: 60, 30, 15, 7.5, 3.75, 1.875, and then 0.94. That is seven questions, and after the seventh there is less than one ordering standing, which means precisely one. Stop at six and you are left with 1.875, which is more than one, so six cannot work for anybody. Now name the thing you just did seven times. One halving is one bit of evidence, and that is the whole of what the word means here. Naming one of 120 costs about seven bits, and one honest yes or no hands you at most one bit, because at best it halves. The count of halvings gets a name as well. We write it lg, so lg 120 is 6.91, and you round it up to seven because there is no way to ask nine tenths of a question.

Five cards is a toy, and the step up to any pile at all is one line of arithmetic you can do yourself. Going from four cards to five multiplies the orderings by five, because the new card drops into any of five places. Multiplying the answers by 5 adds lg 5 questions, which is 2.32. So every card you add costs about the lg of its own position, and the running total is a staircase of bars: 0, then 1, then 1.585, then 2, then 2.32. Add those five and you get 6.91, which is the same seven we counted by hand a moment ago. Ten cards come to 21.8, so about 22 questions, and that one is checkable — 10! is 3,628,800, and 22 halvings takes it under one while 21 leaves 1.73 standing. A million cards cost about 20 questions each (lg 1,000,000 = 19.93), so the staircase looks like 19.9 million from a distance. Its real total is 18.5 million yes-or-no answers, a little lower because the early cards were cheap and the very first bar has no height at all. Fig. 2 draws it one bar per item and will price whatever you think a million costs before it prices the truth. That is the number worth leaving here holding, and not because anyone told it to you. You can rebuild it tomorrow from a staircase you drew yourself.

ONE BAR PER ITEM · HEIGHT lg k · AREA IS THE BILL commit a price for a million items first staircase · lg k flat · lg n each your commit
a million items, sorted by yes-or-no questions. What must that cost, in questions?
how many items — n
commit a price for a million first
what changedNothing yet — a million items, no bars drawn, no total printed. Say what it costs before anything is counted.
why this readingYour number is drawn as a flat row: the same height above every item, that height being your price divided by a million. The staircase is drawn beside it.
what it buysTwo totals side by side, both computed bar by bar rather than quoted — and the distance between them, named.
Fig. 2. One bar per item, height lg k, and the area is the bill. Five cards total 6.91, which is the seven counted by hand; ten total 21.8, and 22 halvings takes 3,628,800 under one while 21 leaves 1.73 standing. A million items priced flat come to 19.93 million, the staircase itself to 18.49 million, and the 1.44 million gap is one constant per item — because the first bar has no height at all.

02The same arithmetic, in a different currency

Now run that same recipe on a smaller question and watch it come unstuck. Forget the full order. I only want to know which of the five cards is the smallest. That is five possible answers instead of 120, so the evidence you need is lg 5 = 2.32 bits. At one bit a question, the floor rounds up to three. Commit to that number before you go any further. Fig. 3 deals you the five cards and exactly three comparisons, and it never once tells you that you are wrong. It prints one readout instead: cards that have never lost. Spend the three the obvious way — 1 against 2, then 3 against 4, then the two winners against each other — and that readout stops at 2. Card 5 was never touched. The bracket winner never lost. Either one could still be the smallest, so you have spent the whole budget and you cannot name an answer. Every other three-comparison plan you try leaves that readout at two or more. The arithmetic was honest and it still was not enough, because a floor is a floor and it was never a promise.

5 answers · lg 5 = 2.32 bits · one bit a question · floor 3 THE FIVE CARDS 1 2 3 4 5 commit first: is three enough? CARDS THAT HAVE NEVER LOST LOSERS SO FAR WHAT THE EVIDENCE ALLOWS convention · a card is ruled out only by losing a comparison
Five cards, one question: which is smallest? The counting recipe says three comparisons. Before you spend one — is three enough?
first card
second card
commit an answer to start
what changedNothing yet. Five cards face down, one question — which of them is smallest — and a budget the counting recipe already fixed at three.
why this readingFive possible answers is lg 5 = 2.32 bits of evidence, and one yes-or-no comparison hands you at most one bit, so the floor rounds up to three. Say whether three will be enough before you spend any of it.
what it buysA number you committed to while the cards were still face down — which is the only way the three comparisons you are about to spend will tell you anything.
Fig. 3. The counting recipe says three, and three is honest. Spend them the obvious way and the readout CARDS THAT HAVE NEVER LOST stops at 2 — the bracket winner and the card nobody touched — so no answer can be given. Count losers instead: four cards must be known to have lost, one comparison makes at most one loser, so four, and any bracket reaches it. Floor 3, truth 4.

So go and count something else. To be known not to be the smallest, a card has to have lost at least one comparison. Short of that it is still a candidate, and you have no grounds to rule it out. Four of the five cards must therefore end up as known losers. And one comparison produces at most one new loser, since only one of the two cards involved goes down. Four losers wanted, one loser bought per comparison, so four comparisons. Fig. 3's second row redraws those same five cards as a knockout bracket, and the tournament says it straight back to you: five players, four matches, four losers, one champion. Every match makes exactly one loser, and every card but the smallest loses exactly once. Four is also a number you can actually hit, because any bracket at all hits it. So this one is not a floor. It is the exact cost. Keep the ledger the figure leaves you holding: floor 3, truth 4.

Now set the two derivations side by side, because they are one piece of arithmetic done in two currencies. Seven questions for the full order: you needed about 6.91 bits of evidence, and one yes-or-no answer hands you one bit. Four comparisons for the smallest: you needed four known losers, and one comparison hands you one loser. Same shape, twice.

cost = (evidence the answer needs) ÷ (evidence one operation gives you)

That fraction is every speed limit on this page, and it has been hiding in plain sight both times. In both derivations the bottom number is 1. A division by one does not look like a division. It looks like a count, and that is exactly why the interesting half of this fraction has gone unnoticed so far.

So go and move the bottom number. Suppose a question could come back with one of four answers rather than two. Decide now what that does to the seven: nothing at all, half of it, or something you have not guessed. Each four-way answer is worth two halvings, so 120 drops to 30, 7.5, 1.875, 0.47. Four questions where you needed seven, and the only thing that changed was the bottom of a division. Fig. 4 sets both derivations under one pair of labels and then turns that denominator into a dial. Two, three, four or five answers per question give floors of 7, 5, 4 and 3. The halving chain is redrawn each time, so you count the steps rather than trust the division. Both derivations sit under the two labels the fraction was born with: evidence the answer needs on top, evidence one operation gives you underneath. You have now moved that bottom number with your own hand, which makes the next question yours to ask rather than mine. What has been holding it at one bit all this time?

THE FRACTION EVIDENCE THE ANSWER NEEDS EVIDENCE ONE OPERATION GIVES YOU THE OTHER DERIVATION FLOOR THE CHAIN answers still standing commit an answer first convention: the chain stops when one answer is left — at most 1, not below it
Seven questions, because each one is worth one bit. Now suppose a question can come back with one of four answers instead of two. What does that do to the seven?
answers per question — the denominator
what I asked for — the numerator
commit an answer to run the chain
what changedNothing yet. Both derivations are on screen under one pair of labels, and both read 1 on the bottom — one bit per question, one loser per comparison. Say what a four-answer question does to the seven.
why this readingA division by one does not look like a division. It looks like a count — which is exactly why the bottom of this fraction has gone unnoticed for two whole derivations.
what it buysA number you named before it could be checked. Whatever you say here, the chain will be counted out in front of you rather than divided behind your back.
Fig. 4. Both derivations under one pair of labels, and both read 1 on the bottom — one bit per comparison, one loser per comparison — which is why a division has been passing for a count. Edit the denominator to a four-answer question and the chain runs 120, 30, 7.5, 1.875, 0.47: four questions where seven were needed. Two, three, four or five answers per question give floors of 7, 5, 4 and 3, with the chain redrawn each time.

03You proved something about two numbers

Something has to pin that bottom number down, and it is not a fact about the cards. A fraction only binds if you can say what one question is worth. Saying that means writing down what you are not allowed to do. Fig. 5 makes you build the pin yourself, by hand, and it opens by dealing the five cards back out. You get a budget of six questions and one job: sort them. You choose every comparison. The widget expands both answers every time, so what grows on screen is your entire procedure rather than one lucky path through it. A leaf ledger counts as you go. Nothing is revealed and no verdict is offered until the sixth question is spent. Then the ledger stops climbing. Six questions, both branches every time, is at most 2⁶ = 64 leaves — and there are still 120 orderings on the board. Two decks light up sitting in the same leaf: b<a<c<d<e and b<a<c<e<d. Your procedure hands back one answer to two different shuffles, so it is wrong on at least one of them.

Build a six-question sorting procedure by hand and watch it come up short, erase the loops off two real sorts, then read the sentence back with both of its numbers in your own hands.
questions chosen 0 of 6 · orderings on the board 120 YOUR SIX QUESTIONS ALL 120 ORDERINGS OF THE FIVE CARDS CONVENTION · the same six questions get asked on every branch. The 64-leaf ceiling holds for adaptive procedures too. the erasure · loops, swaps and index arithmetic thrown away WHAT I AM ALLOWED TO DO compare two items and learn which is bigger — the entire list LEAVES A TREE OF THAT DEPTH CAN HOLD · axis is depth 0 to 10 Neither tree knows it came from a loop. That is what the erasure bought. — questions to single out one of — answers WHAT I ASKED FOR ÷ WHAT I MAY ASK THE THREE ROWS · each fills when you make that edit yourself Nothing here returns one of five answers yet. Buying one is a later job. choose six, then commit an answer count
Five cards, 120 orderings, a budget of six questions. Pick the six comparisons your procedure asks. Both answers get expanded every time.
the ten comparisons available
how many different answers can those six produce?
Two real sorting procedures, the same five cards. Erase the loops, the swaps and the index arithmetic, and see what is left standing.
inspect one
Both brackets are yours. You wrote the top one when you asked for the full order, and the bottom one when you agreed comparing was the only legal move.
what I asked for
what I may ask
choose six comparisons to start building
what changedNothing yet — 120 orderings on the board and not one question asked. The procedure is yours to build, and no answer exists until the sixth question is spent.
why this readingSix questions with both answers expanded every time is at most 2⁶ = 64 leaves. Whether 64 boxes can hold 120 orderings is the only thing this figure is asking.
what it buysA wall you built yourself, so that when it turns out to be everybody's wall you already know exactly why.
Fig. 5. Six questions, both branches expanded every time, is at most 2⁶ = 64 leaves against 120 orderings — so some leaf holds at least two, and yours holds b<a<c<d<e and b<a<c<e<d together. Erase everything that is not a comparison outcome and insertion sort is a tree at most 10 deep, merge sort 8; both have room to spare and both must still carry all 120. Then the sentence reads back with both numbers editable: 2.32 ÷ 1 floors at 3, 6.91 ÷ 2.32 floors at 3 with every number underneath it different, and 2.32 ÷ 2.32 floors at 1.

You did not fail. Put 120 orderings into 64 leaves and some leaf has to be holding at least two (120 ÷ 64 = 1.875). Read that claim carefully, because it promises less than it appears to. One leaf could be holding 57 orderings while the other 63 hold one each, and the count cannot tell those cases apart. All it gives you is that one collision exists somewhere. One is enough, because a procedure that answers two shuffles identically is broken on one of them. So six questions cannot sort five cards, and that is not a statement about your six. It is true of mine and of everybody's — as long as the only thing anyone is allowed to do is compare two cards and learn which is bigger. Fig. 5 boxes the word only on screen the moment it first uses it, and that box stays up for the rest of the page.

Six questions on one deck is still a small claim, though. Stage two of Fig. 5 turns it into a claim about every procedure there will ever be. Two real sorting methods run on the same five cards, and everything that is not a comparison outcome gets erased: loops, swaps, index arithmetic, all of it. Insertion sort costs at most 10 comparisons on five items (1 + 2 + 3 + 4), so what survives the erasure is a tree at most 10 deep, with room for 1,024 leaves. Merge sort splits five into three and two and costs at most 8 (3 + 1 + 4), a tree 8 deep with room for 256. Two visibly different trees, both with room to spare, and both still have to carry all 120 orderings in their leaves. Neither tree knows it came from a loop. That is what throwing the loops away bought: reach. So Fig. 5 writes the model down and leaves the card on screen: WHAT I AM ALLOWED TO DO · compare two items and learn which is bigger. The entire list being one line long is the point. A bound binds a model, and a model earns its reach from what it discards.

Which means it is worth reading back the sentence you actually proved. Not sorting is hard. This one: seven [ one-bit ] questions to single out one of [ 120 ] answers. Stage three puts a cursor in both brackets and labels them by cause, what I asked for over what I may ask. It prints the fraction rather than only its answer, and every readout is in bits, because bits are the only thing a fraction like this can divide. Three edits, and you make all three.

Top boxwhich one is smallest. Five answers is 2.32 bits, so it reads 2.32 ÷ 1, floor 3.
Bottom box → a question that can come back with one of five answers. The 120 answers are still 6.91 bits, so it reads 6.91 ÷ 2.32, floor 3 again.
Both at once2.32 ÷ 2.32, floor 1.

The truth of 4 from Fig. 3 sits pinned beside that first row, so the floor never gets mistaken for a promise. The second row lands on the same floor as the first with every number underneath it different, which is the whole reason the figure prints the fraction at all. And the third row is worth naming out loud: a question fat enough to answer the whole thing makes the floor meaningless. That degenerate case is the cleanest proof that the two boxes are separate levers, because together they reach somewhere neither reached alone. One honest note that Fig. 5 will not make for you. Nothing on this table returns one of five answers yet. You are being invited to imagine an allowed question, and buying one is a job for later.

Both of those boxes are yours. You wrote the top one when you asked for the full order instead of the smallest card. You wrote the bottom one when you agreed that comparing two cards was the only legal move. Neither number was handed to you by the problem, and neither of them says anything whatsoever about sorting. You have also already pulled a third lever without anyone telling you it was one — back at the tournament, when you stopped counting bits and started counting losers. So there are three: change what you asked for, change what you may ask, or change what you are counting in. Two of them now have an editable box with your cursor sitting in it, and that is not a diagram of a proof. It is the design brief for two entire families of algorithm, and the rest of this page is us going out and buying them. We start at the top box, because asking for less needs no new equipment and nobody's permission.

04Ask for less

So edit the top box, and ask for something worth having. The smallest card is not it. You bought that one for four comparisons at the bracket, with no recursion and no cleverness, and there is nothing left to save. Ask for the middle one instead. Out of a million items, which is the median? That is one of a million possible answers, so the evidence you need is about 20 bits (lg 1,000,000 = 19.93) and the floor is twenty questions. Set twenty against the 18.5 million the full order costs, and the edit has already paid for itself on paper. Now go and collect it. The bracket is no help here at all. Knowing that card 7 lost to card 3 says nothing about where either of them sits in the pile. To call something the median you have to know how many items are below it, and losing a match never reports that. The only method you currently own is to sort the lot and read the middle position. Round the million up to 1,048,576 first, because that is 2²⁰ and it makes the levels come out whole, so the middle is position 524,288. That sort is 20,971,520 comparisons (1,048,576 × 20) to learn one thing. You would put 1,048,575 items in order to find out about one.

What you want is an operation that hands you a rank without counting one. Fig. 6 deals five values into a row, [3, 7, 1, 9, 5], takes the last one as the split value, and parks two markers at the left edge. Before a single step runs it wants your commitment. Once one forward pass over the row has finished, where will the 5 be sitting: position 1, 2, 3, 4 or 5? Every guess is accepted, and then the pass steps one comparison at a time with its claim printed above the markers. Everything at or left of the slow marker is smaller than 5. Four comparisons and two real swaps later the row reads [3, 1, 5, 9, 7], and the 5 is third. The sorted row is printed underneath, [1, 3, 5, 7, 9], where the 5 is third as well. Nothing in that pass went looking for third place. The pass only ever pushed smaller things left, and the marker's final resting place is the count of things smaller than 5. So the readout says 5 is the 3rd smallest, and nobody counted anything to learn it. Click any other value to make it the split and the pass reruns: whatever you choose lands in its finished position and reports its own rank.

row [3, 7, 1, 9, 5] · split 5 · nothing has run yet 3 7 1 9 5 pos 1 pos 2 pos 3 pos 4 pos 5 i j THE ROW ACTUALLY SORTED positions count from 1 · a swap with itself is not counted commit a landing position first
the split value is the 5 in the last cell. One forward pass is about to run. Which position will the 5 be sitting in when it ends?
split value — pick another
commit a landing position to start the pass
what changedNothing yet — five values in a row, the last one picked as the split, and two markers still parked at the left edge. Say where the 5 ends up.
why this readingThe pass never asks for a position. It only ever pushes smaller things left, so whatever position the split value ends in was not chosen by anybody.
what it buysA rank, from a pass that never counted one — and the sorted row underneath is there so you can check it rather than believe it.
Fig. 6. Commit where the 5 ends up, then step the pass. Four comparisons and two real swaps take [3, 7, 1, 9, 5] to [3, 1, 5, 9, 7], and the sorted row [1, 3, 5, 7, 9] agrees that 5 is third. Nothing went looking for third place — the slow marker's resting place is the count of things smaller than 5, so the rank arrives without anybody counting it.

A rank is exactly the thing that tells you which side to ignore. You want position 524,288, the pass tells you the split value landed 312,000th, so your item is on the right and the whole left block can be dropped unread. A sort would not drop it, because a sort wants everything ordered and you want one item. So delete one line, one recursive call, and see what goes with it. Fig. 7 builds two trees from identical partition steps on the same 1,048,576 items (2²⁰), and greys out the second call on the right. It asks you first what the deletion saves: nothing, a bit, half, or ten times. Half is the honest guess, and the figure prints it without comment, because you did delete one call out of two. Then both ledgers run level by level. The left tree charges the full 1,048,576 at every one of its 20 levels, a flat rectangle, 20,971,520 in total. The right tree charges 1,048,576, then 524,288, then 262,144, on down, which is page 2's accounting sheet converging to 2n: 2,097,152. Ten times, not two. And the gap widens with n, because it is lg n ÷ 2. A thousand items give 5, a billion give 15. The logarithm was the price of ordering things you were going to throw away.

n = 1,048,576 = 2^20 · lg n = 20 levels BOTH SIDES RECURSED ONE SIDE GREYED OUT assumed throughout: every split lands exactly in the middle commit what the greyed call saves first
one of the two recursive calls is greyed out. Nothing else changes. How much does deleting it save?
how many items — n
commit a saving to start the ledgers
what changedNothing yet — two identical partition trees over the same 1,048,576 items, and one call on the right is greyed out. Say what that deletion is worth before either total runs.
why this readingTwo calls became one, so half is the honest guess, and it is the one almost everybody makes. The ledgers are about to be added up next to each other, and neither of them will say a word about your answer.
what it buysA rectangle against a converging sum — and the difference between them is not a constant, which is the part a factor of two cannot express.
Fig. 7. Half is the honest guess, and it is printed without comment. Then both ledgers run on the same 1,048,576 items: the two-sided tree charges the whole array at all 20 levels, 20,971,520, while the one-sided tree charges 1,048,576, then 524,288, then 262,144, converging on 2,097,152. Ten times, not two — and the ratio is lg n ÷ 2, so it grows. Both totals assume every split lands in the middle, which is what the next figure repairs.

Both of those totals rest on something the figure says out loud, and I will say it again here: every split landed in the middle. That is a good day, and nobody gets to order good days. Suppose the split value comes back the smallest every single time. Then the side you keep holds n−1 items, and you have spent a whole pass to shave off one. The total runs to about 550 billion comparisons on the same 1,048,576 items (n²/2), against the two million you were promised. So go and buy a split value you can prove is near the middle. Fig. 8 lays 25 values out as five columns of five and sorts each column with the smallest at the top, which puts that column's median in its middle cell. It highlights those five medians, then takes the median of those. Before any shading appears, commit: how many of the 25 are guaranteed to be at least as large as that one? Anything from 5 to 13 is accepted and shaded exactly as you claimed it. Then the honest region is filled in on top of yours. Three columns have a median at least as large as the middle median. Each of those three hands over its own median plus the two cells below it, which are larger still. Three columns, three cells each, nine of the twenty-five.

FIVE COLUMNS OF FIVE — claim a guaranteed count, then watch it get shaded exactly as claimed
25 values · 5 columns of 5 · sorted, smallest at top THE COLUMNS WHAT THE PICTURE VOUCHES FOR commit a count —nothing is shaded yet columns sorted smallest at top · ≥ means at least as large as M
Five columns of five, each sorted smallest at the top. The five column medians are ringed, and M is the median of those five. How many of the 25 are guaranteed to be at least as large as M?
group size
commit a count to start
what changedNothing yet — twenty-five values, five sorted columns, five ringed medians and M among them. Name how many of the 25 the picture can vouch for before any of it is shaded.
why this readingWhatever you claim gets outlined exactly as you claimed it, in the order a column hands its cells over: the median first, then the cells beneath it.
what it buysA guarantee that survives any arrangement of the values — and a fraction you can read straight off the drawing instead of off a page.
Fig. 8. Commit how many of the 25 are guaranteed bigger, and whatever you claim is shaded exactly as claimed. Three columns hand over three cells each, so the honest region is nine — while the general rule 3n/10 evaluates to 7.5 here, because small cases come out slightly better. The side you keep is at most 7n/10, the extra call costs 1/5, and 1/5 + 7/10 = 9/10, which sums to 10n. Groups of three give exactly 1 and the ledger stops converging in front of you.

Read the general rule off the same drawing. Half the column medians are at least as large as the median of medians. Each of those columns contributes three of its five, so at least 3n/10 of the array is guaranteed to sit above it. By symmetry 3n/10 sits below, so the side you keep is at most 7n/10. Both fractions came off the picture rather than off a page. One wrinkle, printed rather than hidden: 3n/10 on 25 items works out to 7.5 while the drawing guaranteed 9, because small cases come out slightly better than the general rule. Now the price of the guarantee. Finding the median of the five medians is itself a selection problem on n/5 items, so it is one extra recursive call, and that call is the entire cost. Groups of five spend 1/5 and keep at most 7/10. 1/5 + 7/10 = 9/10, and 9/10 is under 1. So each level of the ledger is nine tenths of the level above, and the whole thing sums to 10n (1 ÷ 1/10). Drag the group dial to 3 and watch it die: 1/3 + 2/3 = 1 exactly, the sum stops converging, and a shrinking ledger becomes lg n equal levels. Groups of 7 give 6/7 and a total of 7n. The number that mattered was never five, it was the slack under 1. So the top box is bought, and bought twice over. Take the lucky pivot and it costs about 2n comparisons when the splits are kind and n²/2 when they are not. Buy the provable pivot instead and it costs a flat 10n whatever the input does. You paid roughly five times the lucky price to delete the bad day, and the bad day was never something you could see coming. The method has a name, median of medians, now that you own the part of it that does the work. And keep the ledger honest on the way out, because the two ends of this section do not meet. The floor said twenty questions and you have just bought the median for two million. The floor never claimed twenty was reachable. It claimed the full order was never the thing you needed, and that part of it was exactly right. Which leaves the bottom box, still sitting at one bit a question, and that is where the next purchase is.

05Ask for more than a bit

So edit the bottom box. It has read one bit since your very first question, and nothing on this table has ever offered more than that. What would a fatter question even sound like? There is one honest answer, and it is the plainest thing in the world: tell me the value. Not which of two cards is bigger, but the number written on the card. Put a price on that, because this page prices everything. If a key is drawn from a universe of u possible values, then one look at it singles out one of u things. So a single look buys lg u bits rather than one bit. For keys in the range 0 to 255 that is 8 bits a look (lg 256 = 8), eight times what a comparison has ever handed over. Now run the page's own fraction on it. Naming an ordering of a million items costs the 18.5 million bits you counted off the staircase. A million looks at keys drawn from a million possible values buy 19.93 million bits (1,000,000 × lg 1,000,000). That is covered in one pass over the data, with a little left to spare. Look at where the spare runs out. The staircase only ever wanted 18.5 million, so the two sides meet a little below u = n, at about 368,000 possible values. That gap is the same 1.44 bits an item the staircase left lying on the table. So the condition reads u is about n, and the word about is carrying real weight.

There is more in that arithmetic than a bigger number. Taking n looks buys n·lg u bits, and n·lg u is exactly lg(un), which is the number of bits it takes to write your input down in the first place. So one look per item always buys you the whole input, whatever u happens to be. Evidence was never going to be the thing that stops you here. What stops you is the array of counters you have to build to use it, and that is a bill this section has not opened yet. And when the value is a whole number in a known range, it stops being evidence at all and becomes an address. Picture a hall filling up before a show, where tickets went out in three groups and the usher walks the queue counting heads: twelve in A, nine in B, fifteen in C. Stop right there and notice what did not happen. Nobody held two tickets side by side to see which one came first. Fig. 9 opens on those three counts and nothing else on screen. So the model card takes a second line, written up while you watch: WHAT I AM ALLOWED TO DO · compare two items and learn which is bigger · read a key as a number.

THREE GROUPS, ONE ROW — name the seat B starts at, and the row is seated from it
A has 12 people · B has 9 · C has 15 · nobody is seated yet THE ROW · SEAT 1 AT THE LEFT type a seat for B, then the row is seated seats count from 1 · the running total counts from 0, exclusive INPUT · n = 8 · VALUES 0 TO 4 COUNTERS · u = 5 · VALUE BELOW RUNNING TOTAL OF THE COUNTERS OUTPUT STEPS n = 8 · u = 5 addresses count from 0 and exclude you · the walk runs forward
An usher counted the queue: twelve in A, nine in B, fifteen in C. Nobody has sat down. Which seat number does group B start at?
what you are looking at
type a seat for B to start
what changedNothing yet — three counts, an empty row, and no rule anywhere on screen. Name the seat B starts at and the usher will seat all thirty-six from it.
why this readingWhatever number you give is obeyed literally. Nothing is marked wrong; the row is drawn and you read the collisions or the empty seats off it yourself.
what it buysA start seat for every group, worked out by counting heads and nothing else — which is a running total, and a running total is a set of addresses.
Fig. 9. Type the seat group B starts at and the seating runs from it — type 9 and B draws straight over A's last four people. Twelve occupy seats 1 to 12, so 13 is the only place left, and the running total 0, 12, 21 is the same three numbers. The same move on [2, 0, 4, 2, 1, 0, 2, 3] gives counters 2, 1, 3, 1, 1, addresses 0, 2, 3, 6, 7, and an output of [0, 0, 1, 2, 2, 2, 3, 4] with no two items ever compared. Eight steps to count, five to total, eight to place.

That second line is the whole event of this section, and I want to be blunt about what it did. It did not break the floor you built in Fig. 5. Go back to the word Fig. 5 boxed and left standing on screen: only. The tree in that proof was made by erasing everything that was not a comparison outcome, and reading a key as a number is one of the things that got erased. Seven questions to sort five cards is still true, still true of everybody, and still exactly as unbroken as it was. What changed is which model you are standing in, and you changed it deliberately by writing one more line on a card. The new model comes with a floor of its own, and that floor is easy to find. You have to look at every item at least once, because an item nobody looked at could have been anything. So n operations, and no arrangement of anything ever gets under it. Read it as Ω(n), which is the same promise page 1 taught you to read. That floor is not the expensive part of this purchase, though. The expensive part arrives two figures from now, and it is a bill.

Fig. 9 wants one number out of you before anything moves. Group A has twelve people and group B has nine. Which seat does group B start at? Any answer is accepted, and the seating then runs from it. Type 9 and group B's block draws itself from seat 9, straight over A's last four people, and you watch the collision instead of being told about it. Type 13 and it fits with nothing to spare. Nobody states the rule, because the drawing is the rule: twelve people occupy seats 1 to 12, so the next block has nowhere to begin except 13. Three groups, three starts, 1, 13 and 22. The running total sitting behind those starts is 0, 12, 21, the same three numbers you just reasoned out by hand. A takes seats 1 to 12, B takes 13 to 21, C takes 22 to 36, and 36 is 12 + 9 + 15. Then the figure makes the same move on an array. Eight values, every one of them between 0 and 4: [2, 0, 4, 2, 1, 0, 2, 3]. Five counters collect them, two 0s, one 1, three 2s, one 3, one 4, which totals the eight you started with. Run a total across those counters and you get 0, 2, 3, 6, 7. The figure relabels that row ADDRESSES and walks the input forward. The first item is a 2, so it goes to out[3] and the address for 2 steps on to 4. The next is a 0, so it goes to out[0] and the address for 0 steps on to 1. Eight placements later the output reads [0, 0, 1, 2, 2, 2, 3, 4], and not one pair of items was ever compared.

A step counter runs beside all of that, and it splits the work into three honest parts: 8 steps to count, 5 to run the total, 8 to place, twenty-one in all. Now look at which number is driving which part. Counting costs 8 because there are eight items, and placing costs 8 for exactly the same reason. The running total costs 5 because there are five possible values, and it would still cost 5 if you handed that same range eight million items. Two different sizes, doing two different jobs, and only one of them is the size of your data. The method has a name now that you own the part of it that does the work: counting sort. The running total earns a name of its own, because it turns up a long way from here in buffer layout and in parallel work: prefix sum. And the two sizes get named here as well, because the next figure charges you for confusing them. n is how many items you have. u is how many values could exist.

Fig. 10 pins the item count at 1,000 and hands you a slider on key width, from 4 bits up to 32. It asks for your verdict before you touch it: is a 32-bit key fine, tight, or impossible on a normal machine? Fine is a reasonable answer, and the figure accepts it without comment, because on memory alone it very nearly survives. A 32-bit key means 4,294,967,296 counters (2³²) at four bytes each, so 16.0 GiB (17,179,869,184 bytes). On a 32 GB machine that fits, and the reader who said so was right. So the figure declines to argue about memory. It prints a second readout instead, labelled steps before the first item is placed, and that one reads 8,589,935,592 against a thousand items to sort. Your answer stays on screen beside it. The derivation is printed rather than asserted, because a number that size reads as a boast otherwise. Zeroing the counters is 2³² steps. Running the total across them is 2³² more. The only steps in there that ever look at your data are the thousand sitting between those two passes, so the item count is a rounding error on eight and a half billion. The counter bar is drawn at the same pixels per unit as the data bar, so it leaves the stage and keeps going for 4,294,967 stage-widths while the data bar stays a thumbnail. Now slide back down and the neighbourhood changes fast, because eight-bit keys want only 256 counters against 1,000 items, about a quarter of the data. Sixteen-bit keys want 65,536, already 65.5 times the data. That is the bill for the second line on the card, and it lands in time long before it lands in memory. You cannot afford the universe. You can comfortably afford 256 counters, and that is the whole of the next idea.

key width — bits · items to sort 1,000 · counters — MEMORY counters × 4 bytes STEPS BEFORE THE FIRST ITEM IS PLACED zero the counters count the 1,000 items run the prefix sum before item one BOTH BARS AT THE SAME PIXELS PER UNIT counting one step per counter touched, four bytes per counter call it first — fine, tight, or impossible
A thousand items, keys 32 bits wide. Counting sort wants one counter per possible key value. On a normal machine, is that fine, tight, or impossible?
key width — bits
call the 32-bit key before the bill is drawn
what changedNothing yet — a thousand items, a 32-bit key, and a counter array nobody has sized. Say whether that is fine, tight or impossible before anything is drawn.
why this readingOne counter per possible value, not one per item. The two sizes have names now: n is how many items you have, u is how many values could exist.
what it buysA bill in steps rather than in bytes — and the item count turns out to be a rounding error inside it.
Fig. 10. Fine is a reasonable verdict and it very nearly survives on memory alone: 4,294,967,296 counters at four bytes is 16.0 GiB, which a 32 GB machine holds. So the figure does not argue about memory. STEPS BEFORE THE FIRST ITEM IS PLACED reads 8,589,935,592 against a thousand items to sort — 2³² to zero the counters, 2³² to run the total across them, and the item count a rounding error between the two. Drawn at the data bar's scale, the counter bar runs 4,294,967 stage-widths off the stage.

06Pay it in instalments

Two hundred and fifty-six counters is an odd thing to be able to afford, so look hard at what it buys. A 32-bit key is four 8-bit digits, and that is the whole of the arithmetic (32 ÷ 8 = 4). A digit eight bits wide has 256 possible values, so a pass that reads one digit wants 256 counters (2⁸) and not one more. Counting sort runs on that unchanged, exactly as Fig. 9 built it. So run it four times, one digit per pass. The universe of keys has not shrunk at all and is still 4,294,967,296 values wide. What shrank is the universe you look at in one go, by 16,777,216 times, and it costs four passes instead of one. That leaves a single thing undecided, and your gut has already decided it. Which digit do you sort by first?

Fig. 11 deals six two-digit keys, [45, 21, 43, 25, 41, 23], and gives you two passes to spend. It takes your commitment before either pass runs: tens digit first, or ones digit first? The tens digit is what most people say, because the tens digit matters more, and the figure runs that choice in full without a word of warning. Pass one on the tens builds two tidy piles and the row reads [21, 25, 23, 45, 43, 41]. Pass two on the ones runs across the whole array the way you wrote it, and out comes [21, 41, 23, 43, 25, 45]. The grouping the first pass built is gone. Nothing is marked wrong, because nothing needs to be. The row is sitting there unsorted and you can read it yourself. Then the figure prints the honest note, because most-significant-first is not broken. It works if each pile becomes its own separate problem, sorted on its own, and never mixed back in until the end. With 8-bit digits that is 256 separate problems after the first pass, each with its own bounds to carry. One label, made where it is made: the figure uses two-digit base-10 keys so the digits are readable on screen, and the mechanism is the one the prose just priced in 8-bit digits.

two base-10 digits per key, so the digits are readable on screen. The prose's digit is 8 bits of a 32-bit key — same mechanism, wider digit.
keys 45, 21, 43, 25, 41, 23 · first pass — · walk — BUCKETS commit a first digit, then both passes run INPUT AFTER PASS 1 AFTER PASS 2
Six keys, two passes to spend. Which digit do you sort by first?
first pass reads
placement walk — Fig. 9
commit a first digit to run
what changedNothing yet — six keys, two passes, and one decision nobody has made. Say which digit the first pass reads.
why this readingThe tens digit is worth more than the ones digit, so sorting by it first is what almost everyone picks. That choice will be run in full, exactly as written, with nothing marked wrong.
what it buysA row you can read for yourself at the end, and a price tag on the arrangement that produced it.
Fig. 11. The tens digit is what most people pick, and it runs in full: pass one gives [21, 25, 23, 45, 43, 41] and pass two, across the whole array, gives [21, 41, 23, 43, 25, 45] with the grouping gone. Least-significant-first, the same two passes give [21, 41, 43, 23, 45, 25] and then [21, 23, 25, 41, 43, 45]. The toggle is not a black box — it is Fig. 9's placement walk, forward or backward, and backward reads [25, 23, 21, 45, 43, 41]. Most-significant-first is not broken; it costs 256 separate sub-problems.

Run it the other way and the same two passes sort the row. Pass one on the ones digit gives [21, 41, 43, 23, 45, 25]. Pass two on the tens digit gives [21, 23, 25, 41, 43, 45], and that is sorted. Look at where 21, 23 and 25 ended up. All three have a tens digit of 2, so the second pass had no opinion about them whatever, and it left them in the order the ones-digit pass had already put them in. That is the property carrying the whole scheme, and Fig. 11 lets you switch it off. The toggle is not a black box labelled stable or not stable. It is the placement walk from Fig. 9, forward or backward. Flip it to backward and the output reads [25, 23, 21, 45, 43, 41]. Ties came out reversed, the ones-column order the second pass was supposed to be carrying is scrambled, and you are watching it happen rather than being told about it. So the name goes on here. A sort is stable when it leaves equal keys in the order it found them. Instalments compose only when a pass never undoes the last one, and that guarantee lives in the sort you used, not in the loop you wrote. Reading a key digit by digit like this is called radix sort. You are still holding one number I chose for you, and it is 8.

Fig. 12 puts that 8 on a dial running from 4 bits to 24, with the key fixed at 32 bits and a million items to sort. It wants a verdict first: for a million items, is the best digit width 4, 8, 16 or 24? Eight is what nearly everybody says, because eight is what I used, and the figure prices it in full rather than arguing with it. One pass costs the million placements plus a walk over the counters, so an 8-bit pass costs 1,000,256 units. Four passes, 4,001,024 in all (4 × 1,000,256). Then the whole curve is drawn and 16 bits comes in at 2,131,072, a little over half of what your 8 costs. The reason it is not a clean half is the counter array: 131,072 counter-steps at 16 bits against 1,024 at 8. Nobody corrects you. Your 8 stays on screen as a marked point on a curve whose lowest point is somewhere else. The two costs are drawn as separate lines so you can see which one moved. Wider digits mean fewer passes, and 16 is the widest digit that cuts 32 into two equal chunks. A 24-bit digit takes two passes as well, so it does not lose on pass count at all. Wider digits also mean an exponentially bigger counter array, and by 24 bits its 16,777,216 counters have swamped the million items and the total is 35,554,432. Then the item count becomes a second dial, and the lowest point moves under it. A thousand items want 8-bit digits and 5,024 units of work, where 16-bit digits would cost 133,072. A million items with the same 32-bit key want 16. The best digit width is not a property of the key. It is a property of the key and how much data you have. One last reading off that screen, and it is the uncomfortable one. At a million items radix does about 2.13 million units of work against the 19.93 million comparisons a comparison sort needs (n lg n), nine times fewer. The comparison sort can still win. Big-O is not a decision procedure, and the reason this one can lose is something the page has not priced yet: where the data physically sits. I am not putting a number on that here. The last idea on this page is where that number gets earned.

key = 32 bits · one pass = n + 2^d units n = 1,000,000 items commit a digit width first — nothing is drawn until you do total placements counter steps d, bits →
32-bit keys, a million items, and the digit width is yours. Which width sorts them for the least work?
digit width — d
how much data — n
commit a digit width to draw the curve
what changedNothing yet. A 32-bit key, a million items, and one knob nobody has turned. One pass places all n items and then walks its 2^d counters, so a pass costs n + 2^d and the whole sort costs that times the number of passes. Name the width before any of it is drawn.
why this readingEight is the width the prose used, so eight is the width almost everyone names. It is not marked wrong here. It is priced.
what it buysTwo costs pulling opposite ways: wider digits buy fewer passes and pay for them with an exponentially larger counter array. Where they cross is the answer, and it does not sit still.
Fig. 12. Eight bits is the answer nearly everybody gives, and it is priced in full: four passes at 1,000,256 units, 4,001,024. Then the whole curve is drawn and 16 bits comes in at 2,131,072, because 16 is the widest digit that still cuts 32 into two passes. At a thousand items the same key wants 8 bits and 5,024; at 24 bits the counter array alone is 16,777,216 and the total is 35,554,432. The best digit width is not a property of the key. It is a property of the key and how much data you have.

There is one more instalment plan, and it starts by killing a misreading. The trouble was never that you do not know the range. A range can be perfectly well known and completely useless. House prices from 0 to 2,000,000 want 2,000,001 counters, which for five thousand houses is 400 counters per house. Any float between 0 and 1 fails differently and worse, because between any two of them there are more of them, so a counter per value is not something you can even define. What you might know instead is how the values are spread, and a spread is enough to compute an address. Carve the mass into n slices holding about one item each, drop each item into its slice, then tidy each slice with an ordinary comparison sort, which is free at size one and quadratic at size n. Fig. 13 spreads a hundred values over a hundred slices with a skew slider sitting at zero. Commit before you touch it: if the data all crowds into one slice, does the cost stay put, get a bit worse, or change shape? Every answer is accepted, and then you drag. The slices empty one by one, the items funnel into the last one standing, and the readout climbs from 100 to 10,000. A hundredfold, and it is a hundredfold because the comparison sort inside that one slice is quadratic. Then the readout is relabelled as what it always was: the sum of the squared slice sizes. A hundred slices of one gives 100. Ten slices of ten gives 1,000 (10 × 10²). One slice of a hundred gives 10,000 (100²). The condition was never that your data is uniform. It is that the squares stay linear. That is bucket sort, and the model card takes a third line while you watch: know how the values are spread. Still the same purchase, a fatter question bought on a weaker assumption each time. Now notice what every address on this page has had in common. It had to put the item in the seat it will hold in the finished order, and that is the last assumption left to drop.

n = 100 items · 100 slices · skew 0 · occupied 100 WHERE THE HUNDRED ITEMS SIT WHAT IT COSTS INNER SORT · Σ sᵢ² TOTAL · 100 + Σ sᵢ² + 100 cost = scatter 100 + Σ sᵢ² inner comparison sort + gather 100 one bar = one slice · spread as evenly as possible · a hairline = 1 item
A hundred values, a hundred slices, one item each. Now suppose every value crowds into a single slice. What happens to the cost?
commit an answer to unlock
what changedNothing yet. A hundred items sit one to a slice and nobody has said what crowding would cost. Say it first — the slider stays locked until you do.
why this readingThe scatter and the gather each touch every item once, so they cannot move. Everything that can move is inside the slices, and what is inside a slice is an ordinary comparison sort.
what it buysA cost you watched change shape rather than a rule about uniformity — and a name for the thing that was actually being assumed.
Fig. 13. Drag the skew and the slices empty one by one while the readout climbs from 100 to 10,000 — a hundredfold, because the comparison sort inside the one slice left standing is quadratic. Relabelled, the readout is what it always was: the sum of the squared slice sizes. A hundred slices of one give 100, ten slices of ten give 1,000, one slice of a hundred gives 10,000. The condition was never that the data is uniform.

07Stop asking for an order

So drop order-preservation — not because the address function is easier without it, though it is. Drop it because the thing that assumption was buying is a thing I have stopped wanting. I do not want a finished sequence at all. I want to put an item down and find that one item again later, and nothing else. Name the loss first, because it is real and it never comes back. The output is not in order, and no amount of care will make it so. Ask this structure for its smallest key and it has nothing to say. What you get in exchange is that the address function stops having to respect anything. It no longer has to send smaller keys to smaller addresses, because there are no smaller addresses. It can be computed from an integer, a string, a whole record. That freedom is not a bonus. It is the exact thing order-preservation had been charging you for, and you only see the price once you refuse to pay it.

So write the freest address function there is. Ten slots, numbered 0 to 9, and a key that is a whole number. Send key k to slot k mod 10, the remainder after dividing by ten. Key 37 goes to slot 7, and key 82 goes to slot 2. No range to know, no spread to assume, and not one comparison anywhere: one division and you are holding an address. The function is a hash function and the array it addresses is a hash table, and neither word does any work the arithmetic has not already done. Now insert 47 — 47 mod 10 is 7, and slot 7 is already holding 37. Two keys, one slot, and the whole idea in trouble on its second insertion. The word for that is collision, and the useful question is whose fault it was.

Not your data's — yours, and it was settled the moment you chose the function. Say your keys can be any number from 0 to 999. That is 1,000 possible keys arriving at 10 slots, so some slot is the destination of at least 100 of them (1,000 ÷ 10). The arithmetic is the whole argument, so run it backwards. If every one of the ten slots owned 99 keys or fewer, the ten together would own at most 990 (10 × 99), and ten keys would have nowhere to go. Now notice what that sentence never mentioned. It never mentioned your data. Fig. 14 hands you four functions and a box to type your own, and it makes you commit before you choose: does anything on that list dodge collisions completely? Then it runs whatever you picked across all 1,000 possible keys and draws the ten columns. The MAX POSSIBLE KEYS PER SLOT readout will not fall below 100 for anything you can write. Nobody there tells you to stop hunting. You watch the counter refuse to move. So the design question was never how to avoid a collision. An input that collides always exists, so the real question is what you do when one arrives.

POSSIBLE KEYS OWNED, PER SLOT commit an answer first MAX POSSIBLE KEYS PER SLOT expressions reduce mod 10 REAL KEYS, ACTUALLY INSERTED
1,000 possible keys, 0 to 999, into 10 slots. Before you pick: does any hash function — one of these, or one you write — dodge collisions completely?
pick a function — it runs over all 1,000 keys
real keys inserted — n
commit an answer to start the hunt
what changedNothing yet — 1,000 possible keys, ten slots, and no function chosen. Say first whether anything you could write dodges collisions.
why this readingA hash function is a rule from 1,000 things to 10 things. Nothing about your data has been mentioned yet, and nothing about it will be.
what it buysA counter you can attack for as long as you like — and a second panel that stops arguing about the universe and inserts real keys instead.
Fig. 14. Every function you pick, including one you type yourself, is run across all 1,000 possible keys, and MAX POSSIBLE KEYS PER SLOT never falls below 100 — because ten slots owning 99 each would own only 990 of them. Then the separation that matters: 5k mod 10 obeys the same pigeonhole and puts 500 possible keys in slot 0, 500 in slot 5 and none at all in the other eight. Collisions are forced; clustering is the function's own doing. Five real keys into ten slots land clean 30.2% of the time — a minority, printed rather than reassured about.

Forced is not the same as fair, though, and the second row of Fig. 14 is the separation worth the whole figure. Try 5k mod 10, which obeys the pigeonhole exactly as the others do. It also puts 500 possible keys in slot 0 and 500 in slot 5 and none at all in the other eight (5k is 0 or 5, never else). Same forced minimum, an entirely different disaster. Collisions are forced. Clustering is your function's own doing. And "some slot owns 100 possible keys" is still not "a hundred items collide", which is why the figure's second panel stops reasoning about the universe and inserts five real keys instead. With an even function those five land clean, no collision at all, 30.2% of the time (10×9×8×7×6 ÷ 10⁵). Print that number rather than reassure with it, because 30% is a minority. So handle the collision instead of hoping about it. The plain way is to hang the keys that share a slot off it in a list, a chain, and to walk that list when you arrive. Then the one dial you have is items over slots, n/m, and it is not a ratio to admire. It is the average chain length, literally. Five keys in ten slots reads 0.5, and thirty keys in ten slots reads 3.0. Its name is α, and the name is worth far less than the number standing beside it.

Now count what those chains cost. A chain is pointers, and every pointer is memory that could have been another slot. Lower α is the only thing that helps you, and slots are the only thing that buys it. So spend the pointer money on slots and drop the chains: when the slot you want is taken, walk forward and take the next free one. Fig. 15 does that with h(k) = k mod 10 and three keys chosen so their walks cross. 37 hashes to slot 7, which is free, and lands in one probe. 47 hashes to slot 7, finds 37 there, steps on to slot 8, two probes. 57 hashes to slot 7, meets 37 and then 47, and settles into slot 9 on its third. To find a key again you replay that same walk: start at h(k), step forward, and stop when you either see your key or hit an empty slot. Searching for 57 costs three probes and gets there. That rule is the entire search, and it is about to break in a way that teaches more than it works.

THE PROBE WALK nothing has been placed yet
Three keys, 37, 47 and 57, all hash to slot 7, so their walks cross. Place them, search 57, then delete 47. The question arrives after the deletion.
which key can you no longer find?
place the three keys to begin
what changedNothing yet — ten empty slots, and three keys whose probe walks are about to cross in the same corner of the table.
why this readingYou have made no choice yet. The one that matters comes after a key is deleted, and it is not the deletion you will be asked about.
what it buysA table with three crossing walks — the only arrangement in which this particular failure can live at all.
Fig. 15. Almost everyone answers 47, and 47 is tested first: not found, exactly as intended. Then search 57 — slot 7 holds 37, slot 8 is empty, the walk stops, and it reports not found on a key highlighted in slot 9. The walk was right to stop: if 57 were in this table at all, slot 8 is where it would have been put. With three of ten slots occupied, somebody else's key settles one slot and empty settles the other seven at once — seven to one, and blanking a slot demolishes the fat question for a key you were not thinking about.

So delete 47, which means blanking slot 8, because that is what deleting obviously means. Before searching again, commit to an answer: which key, if any, can you no longer find? Nearly everyone says 47, and Fig. 15 tests that one first, and it holds up: searching for 47 reports not found, exactly as intended. Now search for 57. Slot 7 holds 37, not it. Slot 8 is empty, so the walk stops and reports not found, on a key sitting in slot 9 and highlighted on your screen. The key that broke is not the key you deleted. And the walk was right to stop, which is the part worth keeping. If 57 were in this table at all, slot 8 is where it would have been put. The emptiness was never missing information. It was the proof. Run that probe walk through the page's own fraction and you can price what you demolished. The answer "somebody else's key" settles exactly one slot and sends you one step further along. The answer "empty" settles the entire rest of the walk in a single look. Those two answers are not worth anything like the same, and a table's whole search cost rests on the fat one. The repair is a marker reading was occupied: search reads it and keeps walking, so 57 comes back in three probes again, and insertion ignores it and reuses the slot, so no space is lost. Do not remember the marker. Remember what it protects: when a search stops, ask what the absence is claiming.

08Buy it once and keep it

That marker was the last thing on this page bought inside a single run, and so was everything before it. The theatre's counts, the prefix sums, the bucket boundaries, the probe walk: each one was built at the start of a job, used once, and dropped on the floor when the job ended. Now look at what the habit costs you. The expensive part of most of those purchases never depended on the question you were asking. It depended only on the data sitting there. So ask the obvious thing. What if you kept it? An index is that question answered yes. It is the same denominator purchase you have been making all page, and the only difference is where the price lands. Buy a fat question inside one run and one run has to pay for it. Buy it once and keep it, and the price spreads over every question you will ever ask. That is why you can afford something here that would be ridiculous inside a single job.

So what is the cheapest thing worth keeping? Hold the data in order, and stop there. No pointers, no nodes, just a row you sorted once and did not throw away. One look pays properly now, because comparing your target against the value in the middle throws away half the row whichever way the answer comes back. Price that on the page's own fraction, because none of it is new. Fifteen values means fifteen possible answers, so naming one costs lg 15 = 3.91 bits. One comparison against one value buys you one bit, so 3.91 over 1 rounds up to four looks, and that is the entire derivation. Fig. 16 lays the fifteen values out in a row and takes your worst case before it lets you step anything: over all fifteen possible targets, what is the most looks any single one of them can cost? Whatever you commit is accepted, and then the figure runs all fifteen searches in front of you and prints the longest. Hunting for 8 is finished in one look. Hunting for 1 touches 8, then 4, then 2, then 1, and costs four. Four is the maximum over all fifteen targets, four is what the division said, and it is the same fraction as the five cards on a smaller numerator.

n = 15 · positions 1–15 · mid = floor((lo+hi)/2) · a look = one comparison THE SORTED ROW — POSITION i HOLDS VALUE i EVERY MIDPOINT EVER USED, AND WHAT HANGS UNDER IT commit a worst case first
fifteen sorted values, and each look throws away half of what is left. Over all fifteen possible targets, what is the most looks any single one of them can cost?
then hunt for one value
commit a worst case to start the run
what changedNothing yet — fifteen values in order, and nobody has looked at any of them. Say what the worst target costs before anything is stepped.
why this readingNaming one of fifteen answers takes lg 15 bits of evidence, and a comparison against one value hands back one bit — so the floor is a division, not an opinion.
what it buysA worst case you measured by running every target, sitting next to a floor you derived — and a count of how much of that work was done twice.
Fig. 16. Commit the worst case and all fifteen searches run in front of you. Hunting for 8 is one look; hunting for 1 touches 8, 4, 2, 1 and costs four — which is what lg 15 = 3.91 over one bit already said. Every midpoint lights up and stays lit, and the union is all fifteen positions in four ranks of 1, 2, 4 and 8. Those fifteen searches compute 49 midpoints between them to produce 15 distinct numbers, so 34 of the 49 re-derive a number another search already had.

The second row is where the figure stops being about searching. Every position ever used as a midpoint lights up and stays lit, and after fifteen searches the whole row is on. Look at the order it lit up in. 8 came first, alone. Then 4 and 12. Then 2, 6, 10 and 14. Then the eight odd numbers. Four ranks of 1, 2, 4 and 8, which totals exactly the fifteen positions you began with. Nobody drew that shape: the searches drew it, and they drew the same one every time, which is what the third row is counting. Each search works out its own midpoints, and the ranks tell you how many: one for the search that lands straight on 8, two each for the pair at 4 and 12, three each for the four below them, four each for the eight along the bottom. That comes to forty-nine computations between them (1 + 4 + 12 + 32). Those forty-nine produce fifteen distinct numbers, which means thirty-four of the forty-nine re-derive a number another search already had. Store the fifteen once and all of that recomputation is over. Take the names while the picture is still in front of you. The value on top is the root, the values hanging under a value are its children, the four ranks are levels, the eight along the bottom are leaves, and walking from the top down is a descent. And the moment that shape is stored, arithmetic stops choosing it for you. The rule (lo+hi)/2 picked those midpoints while they were being recomputed. Now you pick.

So pick the shape out of the key itself, the way you picked the passes in radix sort. Fig. 17 hands you 20-bit keys and reads five bits per level, which is 32 possible chunks and therefore 32 children at every node. Twenty bits covers 1,048,576 possible keys (2²⁰), so the table has room to grow. Type a key and step down, one chunk at a time. Before you type, commit to one thing: the table grows from ten items to a hundred thousand, and the depth does what? Every answer is accepted, and then the growth runs. Items climb 10, then 1,000, then 100,000, while the DEPTH readout sits on 4 and never twitches. The reason is printed right beside it: each level ate five bits of the key, and the key did not get longer when the data did. A balanced search tree over the same 100,000 items is drawn alongside at 17 levels (lg 100,000 = 16.61). The chunk dial is Fig. 12's knob wearing different clothes. One bit per level gives 20 levels and 2 children. Five bits gives 4 levels and 32 children. Ten bits gives 2 levels and 1,024 children. Fewer steps against a wider node, met once in sorting and now again in lookup. And the comparison counter reads zero at every setting, because no level here compares anything. You are back to the key being the address, one instalment per level, and the structure has a name: a trie. One label where it is made: the figure draws the dense case, a node per used prefix, and a real trie on scattered keys pays for the empty children it allocates. That space cost is the same bill the counter array sent you.

20-bit key · 5 bits per level · 32 children · universe 1,048,576 THE DESCENT each group is one level's chunk GROW THE TABLE 10 items · depth — 1,000 items · depth — 100,000 items · depth — SAME 100,000 ITEMS DENSE CASE — one node per used prefix. A real trie on scattered keys also pays for the empty children it allocates: the counter array's bill. commit a prediction first commit a prediction first
the table grows from 10 items to 100,000. The depth of the trie does what?
key — 0 to 1,048,575
bits read per level
commit a prediction to grow the table
what changedNothing yet — a 20-bit key, five bits eaten per level, and a table nobody has grown. Say what the depth does when it goes from ten items to a hundred thousand.
why this readingEvery search on this page so far has divided the data, so the depth followed the data. This one divides the key instead — or it does not, and you are about to find out which.
what it buysA depth you can read off the key alone, before anyone tells you how many items there are.
Fig. 17. Items climb 10, 1,000, 100,000 while the DEPTH readout sits on 4 and never twitches, because every level ate five bits of the key and the key did not get longer when the data did. A balanced search tree over the same 100,000 items is drawn alongside at 17 levels. The chunk dial is Fig. 12's knob in different clothes: one bit gives 20 levels and 2 children, five bits gives 4 levels and 32 children, ten bits gives 2 levels and 1,024 children. The comparison counter reads zero at every setting.

Each node in that trie holds children and nothing else, which is a waste of a good node. So what is the smallest useful fact you could cache inside one? Answer before you read on, and keep the answer small, because small is the point. One bit will do it: is there anything in this region at all? A node covers every key below it, so that single bit speaks for the whole subtree underneath. Arrive at the node, read the bit, and if it says empty you skip the entire region without descending into it at all. "Recurse to find out" has become "look and decide", and it cost one bit per node. That is the cheapest claim on this page worth storing, and the next move cannot be made without it.

Now stop chunking the key from the left and cut it in half instead. A 32-bit key splits into a top 16 bits and a bottom 16 bits, and the top half says which block you are in. One look at that block's summary bit then says whether the block is empty. Either answer leaves you holding a 16-bit problem, and the same move applies to that. Fig. 18 stands two counters side by side, ITEMS REMAINING and BITS OF KEY REMAINING, and makes you name which of the two halves before the step button will do anything. Items remaining is what nearly everybody picks, and it is a fair guess, because every halving on this page so far has halved items. The figure accepts it, wires it to the button, and lets you step. The bit counter goes 32, 16, 8, 4, 2, 1 — five steps, and the key is gone (lg 32 = 5). The item counter sits on a million and does not move once, with your prediction still on screen beside it. Five levels, for any number of items at all.

ITEMS REMAINING BITS OF KEY REMAINING THE KEY · CONSUMED BITS GO DARK commit which counter halves before the step button does anything
A 32-bit key, a million items, and two counters. Which one halves on every step?
key width
items in the table
commit which counter halves to start
what changedNothing yet — two counters, neither of them running, and a key nobody has cut in half. Say which counter halves before the button will move.
why this readingOne step of the structure from the last paragraph runs when you press the button. Something in this figure gets cut in half by it. Decide which of the two counters that is, and the button will do the cutting rather than argue with you about it.
what it buysWhatever your answer buys, priced here in the same figure, in bits and in bytes — including the bill for it, which does not go away and is not meant to.
Fig. 18. Items remaining is the natural pick, and it is wired straight to the step button. Then the stepping runs: the bit counter goes 32, 16, 8, 4, 2, 1 — five steps and the key is gone — while the item counter sits on a million and does not move once. Five levels, for any number of items at all. What bought it is 2³² bits, about 537 MB, which is an order-of-magnitude claim about one bit per possible key and not a measured footprint — 32× cheaper than the counter array's 16.0 GiB, the same universe spent in a different direction.

Before that settles too comfortably, look at what bought it. u again, the whole universe of possible keys, sitting in memory. One summary bit for every key a 32-bit field can hold is 2³² bits, or about 537 MB, and the figure says plainly what that number is. It is an order-of-magnitude claim about one bit per possible key, not the measured footprint of any named structure. Now set it against the counter array. That wanted 2³² counters of four bytes each, 16.0 GiB, so one bit per key comes in 32 times cheaper. The same universe, spent in a different direction. The bill did not go away, and it never does. You looked at it and decided you could afford it, which is a different sentence and an honest one. One last reading before those counters leave the screen. This figure halved the key. The next one halves the data, and a billion items halved takes 30 steps (lg 10⁹ = 29.9). Five against thirty, the same fraction both times, and all that changed is which quantity you put on top.

09You are not billed in comparisons

Every count on this page has treated operations as if they cost the same. They do not, and the gap is not small. Fig. 19 pins a billion keys on the table and hands you one dial, the fanout of a node, running from 2 up to 1,000. Two meters run beside it. One counts COMPARISONS PER LOOKUP, and the other counts FETCHES PER LOOKUP, where a fetch is one read of a page off the disk. A page is the smallest lump the hardware will hand you, a few thousand bytes, whether you wanted one key out of it or a thousand. Before the dial will move, the figure makes you commit to which meter you are trying to make small. Comparisons is what nearly everybody picks, and it is a fair answer. Comparisons are the only currency this page has used for thirty steps. So the figure takes your answer and optimises it honestly. It drives the dial to the setting with the fewest comparisons, which is fanout 2, and both meters read 30 there. Then it prices the currency on screen. In the time one page fetch takes, a machine can touch memory on the order of a hundred thousand times. Your optimum was optimal in the currency nobody bills you in.

n = 1,000,000,000 keys · one dial · two meters COMPARISONS PER LOOKUP FETCHES PER LOOKUP THE BILL · MEMORY-TOUCH EQUIVALENTS commit a meter first — nothing is counted yet convention · the in-node scan is LINEAR: all f−1 keys, end to end
A billion keys, two meters, one dial. Before it moves off 2 — which meter should you be making small?
fanout f — children per node
the root
commit a meter to start the dial
what changedNothing yet — a billion keys, a dial sitting on 2, and no number anywhere on screen. Name the meter you think you are trying to make small.
why this readingBoth meters are honest counts of the same lookup. Only one of them is a bill, and the figure will not say which until you have committed.
what it buysA commitment made in the only currency this page has used for thirty rungs — which is the whole reason the price lands when it arrives.
Fig. 19. Comparisons is what nearly everybody picks, and the dial is driven honestly to its optimum — fanout 2, where both meters read 30. Then the currency is priced on screen: one page fetch is worth about a hundred thousand memory touches. Widen the node and comparisons climb 30, 81, 495, 2,997 while fetches fall 30, 9, 5, 3, since 1,000 × 1,000 × 1,000 is a billion exactly. Against the same billion keys in a disk-resident two-child tree — 30 fetches, 3,000,000 touch-equivalents — the fat tree costs 302,997, and its 2,997 comparisons are one percent of the bill. The meter scans the node linearly; a binary search inside it would keep the count near 30.

Now widen the node and watch both meters run at once. Naming one key out of a billion needs about 30 bits (lg 10⁹ = 29.9), and that number never moves. What moves is the bottom of the fraction. One comparison buys one bit, so 30 over 1 is 30 comparisons. One fetch of a node with f children buys lg f bits, because reading that node tells you which of its f branches your key lives in. Levels are therefore 30 divided by lg f, and you can check every setting by multiplication instead. Ten children per node: nine tens multiplied together (10⁹) is a billion, so nine levels. A hundred children clears it in five, since 100⁵ is ten billion and 100⁴ is only a hundred million. A thousand children, and do this one yourself: 1,000 × 1,000 × 1,000 is a billion exactly, so three levels. Keep the root resident in memory, since there is only ever one of it, and the lookup costs two fetches. Meanwhile the other meter climbs. A node with f children holds f−1 keys, and scanning them end to end costs all of them, so comparisons go 30, 81, 495, 2,997. A hundredfold rise, on the meter you said you wanted small.

So price the whole thing, in the currency that bills you. The fair comparison is not against comparisons in memory. It is against the same billion keys in a two-child tree that also lives on disk, 30 fetches deep. At a hundred thousand memory touches per fetch, that lookup costs 3,000,000 touches of equivalent work. The fat-node tree costs three fetches, which is 300,000, plus the 2,997 comparisons it does inside those three nodes. The bill comes to 302,997, which is 9.9 times cheaper, or 14.8 times with the root resident (202,997). Now look at where the 2,997 sits inside that total. It is one percent of the bill. There is the sentence with a number under it at last: you are not billed in comparisons. You bought a hundredfold more of them and the total moved by one part in a hundred, because the thing you do pay for fell tenfold. Every database index on earth is fat for that reason and no other.

Two honest notes before this leaves the screen. The comparison meter only climbs if the node is scanned from one end to the other. Run a binary search inside the node instead and the count stays near 30 at every fanout, at no extra cost, because the node is already in memory once you have fetched it. Fig. 19 states which method its meter uses, and it uses the linear scan, so the climb you watched is the worse of the two. Second, on flash the ratio is far smaller than a hundred thousand. The fetch is still the thing you are billed for, so the shape of the answer holds; only the size of the win shrinks. And now the digit dial closes. Radix sort lost there to a sort with worse asymptotics, and this is what beat it. Each pass scattered items to hundreds of distant addresses, and every scatter dragged in a fresh lump of memory to place one single item. Counting operations as equal was always the fiction. The model card takes its last line — fetch a page — and this one arrives with a price printed beside it.

That is the page, so take it. Fig. 20 reopens the model card with three boxes and four questions this page never solved. How many answers could there be. What does one allowed operation tell me. What am I counting in. You fill all three and commit a floor, and only then does any answer appear. Look up one word in a 170,000-word dictionary: that is 18 bits (lg 170,000 = 17.4), which is 18 comparisons if comparisons bill you and 2 fetches if page reads do. Same numerator, two right answers, and you picked which. Sort a billion 64-bit keys: you need 2.99×10¹⁰ bits and one key read buys 64 of them, so 0.47 reads per item would cover it. But u is 2⁶⁴, so you buy it in four instalments of 16 bits, and you have just re-derived radix. Then the one that hurts. Find the top ten scores out of a billion: your floor is 299 comparisons and the true cost is a billion, because you have to look at every item. Nobody corrects you. You watch your own correctly-computed floor sit three million times under the truth, which is the five cards arriving again under your own hand. A floor tells you where to start looking, never where you land. The closest pair in a list of 1,000 says it once more, quietly: floor 19, truth about 10,000. A fourth control then asks which lever you would buy, and it reports what you specified rather than what it is called. Shrink the numerator and it describes one-sided recursion. Fatten the denominator to a key read and it describes counting in instalments. Change the currency to fetches and it describes a fat node. The names print last and greyed, because the specification is the part that is yours.

floor = ceil( lg answers / bits per operation ) — a lower bound, never a cost WHAT YOU SPECIFIED 1 · answers could be — 2 · one operation buys — 3 · counted in — YOUR FLOOR AND THE REAL BILL, ON A LOG RULER commit a floor first — nothing is priced until you do
a problem never solved
1 · how many answers
3 · what am I counting in
2 · bits one op buys
which lever would you buy
fill the three boxes, then commit a floor
what changedNothing yet. Four problems this page never solved, three boxes, and no answer anywhere on screen until you commit one.
why this readingEvery box is taken literally. Whatever you put in the three of them is the floor you get — nobody here is going to correct it.
what it buysA number of your own, sitting beside what the problem actually costs, with the distance between them printed and not softened.
Fig. 20. Three boxes, four problems this page never solved, and a floor committed before any answer exists. The dictionary is 18 bits, which is 18 comparisons or 2 fetches depending on which currency bills you — same numerator, two right answers, and you picked which. The top ten of a billion floors at 299 against a truth of a billion, and nobody corrects you; you watch your own correctly-computed floor sit three million times under it. The closest pair says it once more, quietly: floor 19, truth about 10,000.
iolinked.com
Written by Ajai Raj