Field

Structures

Heaps, trees, hash tables and dynamic arrays — each with its advertised bound put through the same measurement as everything else here.
110100257amortised 2.000256512append numbercost of that append (log scale)growth factor 2, cost = 1 write + a copy of the array when it resizes9 resizes in 512 appends

What amortised means

What an amortised bound actually claims, why it is a statement about a sequence rather than an operation, the sawtooth of individual costs behind the constant, and where the distinction between amortised and worst case decides a design.

0%25%50%75%12345×1.125×1.25×1.5×2×3×4capacity left unused at the endamortised cost per append20,000 appends, cost = 1 write + a copy on resizeneither end wins

Choosing a growth factor

The growth factor of a dynamic array measured on both axes at once — amortised cost against wasted capacity — why no choice dominates, and what the memory allocator has to do with the factor 1.5 that several standard libraries use.

keytruthfoldedtreereversed16,3626,8666,8696,86923,0743,5783,5813,58131,9632,4672,4702,47041,3731,9021,9071,95451,0981,6021,6051,60569351,5121,4711,46377691,2801,2851,30686561,1601,1631,16395661,1001,1011,095105101,0511,0361,029shaded rows are keys whose count depends on the order aloneSpace-Saving, k = 32 · 8 shards · hashed37 keys move with the order

The order nobody fixed

Why merging counter summaries is not associative, how far apart the shapes of a merge tree drive the same answer, and what that costs a system that compares summaries rather than reading them.

sorted insertion — height 62shuffled insertion — height 10truncated at depth 1663 keys, identical set, different arrival order62 deep against 10

The tree that is a list

What happens to an unbalanced binary search tree on sorted input, why the degeneration is total rather than partial, and what balancing actually buys measured against the ideal and against the disaster.

10³10⁴10³10⁴10⁵ncomparisonsbottom-up (Floyd)repeated insertionn from 128 to 65,536, random input, seeded1.21× between the two at the right-hand edge

Building a heap from the bottom

Two ways to turn an array into a heap, measured across three orders of magnitude; why the n log n bound describes an input rather than an algorithm; and what the choice costs inside heapsort and inside a priority queue.

root, priority 0.9651.00.0prioritykey24 keys, sorted insertion, seed 20260810height 8 against an ideal of 4

The priority nobody supplied

How a treap repairs the failure mode of a binary search tree without measuring anything, why the shape it produces is the shape a random insertion order would have given, and what the repair costs.

04812162024283236404448slots from homepale: linear probing · dark: Robin Hoodmean 2.384identical for bothworst 48 → 12var 37 → 7435 keys, 512 slots, seed 20260811displacements, counted exactly

The probe nobody waits for

Robin Hood hashing measured against plain linear probing, where the mean is provably unchanged and the variance collapses — the clearest case here of a technique invisible to an average.

column height = keys in that bucket · line = threshold of 8a well-spread hashlongest 44 → 4worst lookupthe low bits onlylongest 3131 → 5worst lookupevery key collideslongest 192192 → 8worst lookup192 keys, 256 buckets, seed 20260811threshold 8, 64 buckets shown

A bucket that becomes a tree

Java's treeify threshold measured under three hashes, why the Poisson argument says it never fires, and what it means to ship a mechanism whose entire value is in somebody else's mistake.

levels on the path (outline) · transfers actually paid (filled)B = 411 levels · 6.99 transfers · 16,384 blocks residentB = 166 levels · 3.23 transfers · 4,096 blocks residentB = 644 levels · 1.99 transfers · 1,024 blocks residentB = 2563 levels · 1.30 transfers · 256 blocks residentB = 10243 levels · 1.01 transfers · 64 blocks residentbinary search over the same 4,194,304 keys: 20 transfersB = 1024, M = 65,536 (M/B = 64)20× between binary search and the widest tree

A tree with nodes the size of a block

The B-tree measured in block transfers against binary search over the same keys, why the fanout is a hardware parameter rather than a design taste, and why the measured cost is below the height.

11010010⁴10⁵queries answeredcharacter comparisons, cumulative5 queriesScan each timeIndex, then queryone unit = one character comparison · 4 doubling roundsbreak-even at 5 queries

The index that is the text

Building a suffix array by prefix doubling, why it makes no character comparisons at all, what Kasai's linear LCP array is doing, and where the break-even against simply scanning the text actually falls.

key 05,416short by 4,163key 1462short by 4,154key 31short by 2,099key 71short by 943key 19401short by 3counter held (bar) against true count (tick)12 counters · 768 bits · no randomnessbound N/(k+1) = 4,615

The items that survive k counters

The deterministic frequent-items structure, its shortfall bound, and a head-to-head against Count-Min at equal bits that comes out the other way from the way the field is usually described.

HyperLogLog1024/1024 identicalCount-Min256/256 identicalbottom-k128/128 identicalMisra-Gries20/36 identicalfraction of the state that merged to the identical value→ 1,974→ 10,291→ 2,322→ 8,766two streams of 30,000 · 2,007 distinct keys in the union3 of 4 merge exactly

The summaries that add

Why register-wise maximum and cellwise addition lose nothing, what a counter table gives up when it merges, and why the distinction decides whether a distributed summary is reproducible.

1234152abcbcbccbsolid: a transition on a character · dashed: a suffix or failure link8 states ≤ 9, 9 transitions ≤ 11

Every substring, in fewer states than substrings

The suffix automaton, the two exact bounds on its size, the strings that attain them, and three unrelated routes to the same substring count.

Count-Min 4×64exact0 under200 overrms 303Count-Sketch 4×64-2,774-1,38701,3872,774120 under80 overrms 256cash register · insertions only, Zipf s = 1.1 · counts exact8,192 bits each

A sketch that is allowed to be under

Count-Sketch against Count-Min at equal bits, why the error changes currency from the L1 norm to the L2 norm, and what is lost when an estimate stops being a bound.

1,8103,6205,4297,239010,00020,00030,00040,000arrivals so farcount of key 1 in the last 4,096Misra-Gries, no clockblocks of Misra-Griesthe truth, and the ring buffera heavy hitter that stops · sampled every 5006,493 claimed, 0 true

The count that outlives its arrivals

Heavy hitters over a sliding window, and why a counter cannot be run backwards — the block decomposition, the slack it cannot remove, and the two errors that go opposite ways.

key 16,726exactkey 23,236exactkey 32,035exactkey 41,440± 2key 3109± 937key 42117± 937key 8402± 937key 14914± 937bracket, with the truth marked · widest 937 · 3 exactcash register · stationary Zipf · 32 countersthe smallest counter is 938

The counter that takes the smallest slot

A counter-based heavy-hitter structure that overestimates — the eviction rule, the error it records beside each count, why the bracket is empty exactly where the answers matter, and the reversal against Misra-Gries.

f = 6,3628/8 holdingf = 3,0748/8 holdingf = 1,9638/8 holdingf = 1,3738/8 holdingf = 1,0988/8 holdingf = 9353/8 holdingf = 7690/8 holdingf = 6560/8 holdingpredicted damage, in arrivals — every row totals 967Space-Saving's shareMisra-Gries's share8 shards · round · k = 32bill 967 arrivals

The bill a partition only divides

Why the merge damage of the two counter structures is one quantity split two ways, how the split is decided by the partition rather than the structure, and what the merge tree adds on top.

folded in one at a time2,616 tuples17 ranks outcombined pairwise, in a tree3,637 tuples17 ranks outfolded in, last shard first2,615 tuples17 ranks outtuples kept, and worst rank error against a promise of 10032 shards · ε = 0.01 · high-biased · round1.39× the space, 0 ranks of answer

The shape that moves the bill

Why the order shards are combined in changes a quantile summary's size by forty per cent and its answers by less than the promise, and why the counter tables behave the other way round.

weighted path lengthΣ wᵢdᵢ — what Huffman minimisescuts takenΣ over the mergesdamageworst error leftchaintreesmallest-firstlargest-first543k147k123k738k309254259388323148183403Misra-Gries · 32 shards · hashedleast path smallest · least damage balanced

The fold that minimises the wrong thing

Why the size-ordered merge fold is provably optimal for the weighted path length and second-best for the damage, and which quantity actually tracks a fold's bill.

counter tablesworst error, ratio to bestquantile summariestuples kept, ratio to bestchain2.18× (323)1.10× (2,807)tree1.00× (148)1.26× (3,211)smallest-first1.24× (183)1.28× (3,278)largest-first2.72× (403)1.00× (2,556)32 shards · hashed · k = 32each column against its own best shape

The shape one structure will not fold

Why a merge fold that saves a quantile summary a fifth of its space costs a counter table 2.7 times its error, and what a deployment holding both structures can do about it.

rank among the boundaries, sorted by the text before themsorted by the text after0 in the rectanglepattern "ss is un"split after 40 end with the left half0 begin with the rightEnglish-like · 2 copies of 512z = 156 · 0 crossing

A rectangle over a permutation

How a wavelet tree over a permutation answers a rectangle query, what the descent and the lifting cost, and why the leaves have to exist even though they hold nothing.

50318223749516674879310811positionthe minimum12 values · depth 3answer 6 (1)

The shape a range question is about

The Cartesian tree, why a range minimum is a question about a shape rather than about numbers, and the stack that builds it in one pass.

024601234567891011level of the wavelet treemean runthe parse's grida uniform permutationbreak-even3,612 points · 12 levels1.23x chance

The runs a permutation does not leave

The run-coded bit vector the deferral asked for, why it costs more than the bits it replaces, and the shuffle control that says how much of the ordering was ever there.

05101520510revisions in the collectiondepthone revision alone: 8worst depthmean depthfourteen revisions of another9 generations added exactly one

One revision, one level

The worst and mean depth of the first k revisions of two real files, the offset a single document contributes, and the saturation that stops the chain deepening.

a fixed-length code97,718 bits5.00 ranks · in orderthe best ordered tree77,890 bits3.98 ranks · in orderthe best tree of any shape76,789 bits3.92 ranks · unorderedσ 21 · the ordered tree is 1.43% above the unordered optimum16,384 characters of englishorder costs 1.43%

The tree the operation insists on

Optimal alphabetic codes computed by dynamic programming, measured against Huffman's tree and against a fixed-length code, on generated and real text.

range consideredminimum atC[at] < lonew document[476, 489)483 · document 4yesyes[476, 483)477 · document 1yesyes[476, 477)476 · document 0yesyes[478, 483)482 · document 2yesyes[478, 482)478 · document 0nono[484, 489)486 · document 3yesyes[484, 486)484 · document 0nono[487, 489)487 · document 2nono8 steps, 5 documents, and the two columns never differrows 476–489 · 8 documents8 steps

A document already in the answer

The chainless document listing written out, the left-first order the equivalence depends on, and the two deliberate defects that must be caught.

051015255075100125documentsdistinct characters the documents end with+7+52+162+293+4+-1+9+19prosecopies of one basethe label is the runsthe cut added128 documents0.15 against 2.31 runs a separator

The price of a boundary is what precedes it

Why cutting a text into documents costs runs in proportion to how predictably the documents end, measured against the run counts it explains.

range minimum and chain838,797255.0%range minimum, no chain285,46086.8%one descent over D119,97236.5%the document array, the chain and a range minimumthe document array, a range minimum and one bit per documentthe document array, in a wavelet tree64 documents · 16,447 characters14.3% of the published apparatus

The last array in the apparatus

What remains of a document-listing apparatus once the previous-occurrence chain and the range minimum have been removed, and why the last part is a different kind of object.

extensions attempted9,206 dead7,594 livebit-vector ranksthe loop: 168,000the descent: 24,0868 patterns · 1 error · sigma 2054.8% dead · 6.98x

The branches that find nothing

A backtracking search's dead extensions counted, and what removing them rather than making them cheaper is worth.

plain bit vector19,475compressed blocks4,55723.4%Elias–Fano3,90520.1%positions, priced as Elias–Fano3,59118.4%16,385 rows · one in 32 markedElias-Fano at 20.1%

A position split in two

The Elias–Fano construction applied to an index's sample marks, what each operation costs, and why the split is where it is.

01,024120 phrases · 1,024 characters60 drawn, every one pointing right

Every copy points right

The ordering property a Lempel–Ziv parse guarantees, and the second time in this collection that a traversal order made a bookkeeping structure unnecessary.

020406080255075100125one sampled position in every …of the plain index, per centsize: 84.7%67.5 steps16,384 characters · 8-character patternssize falls, the walk lengthens

Bits and steps on one frame

The convention that a change trading two currencies is drawn in both, applied to the one dial a self-index's locating apparatus depends on.

0a1b2split3split4a5a6b7split8a9b10split11a12b13split14accept9 character tests · 5 splits · 1 accepting(a|b)*a(a|b)(a|b)(a|b)15 states

Two states per operator

The non-deterministic machine a regular expression compiles to, what its states are, and why the construction's linearity is structural rather than fortunate.

All essays