Worked examples — Chaining — linked lists in buckets, load factor, resizing
Before we start, one reminder of the symbols we lean on the whole page, each in plain words:
The symbol means remainder: because , remainder . That remainder is always between and , which is exactly why it makes a valid bucket index.
The scenario matrix
Every problem chaining can hand you falls into one of these cells. The worked examples below each carry a tag like (C3) so you can see which cell they fill.
| Cell | Scenario class | The edge it stresses |
|---|---|---|
| C1 | Empty / single-key table | and : degenerate, |
| C2 | Light table, no collision | , every key its own bucket |
| C3 | Collision into a shared bucket | two+ keys, chain length |
| C4 | Exactly at the resize threshold | boundary, resize triggers |
| C5 | Heavy / oversized table | (chaining survives) and (waste) |
| C6 | Adversarial worst case | all keys collide → one chain of length |
| C7 | Amortized cost over many inserts | geometric doubling sum |
| C8 | Real-world word problem | mapping a story onto |
| C9 | Exam-style twist | successful vs unsuccessful search formula |
Example 1 — The empty and single-key table (C1)
Step 1 — Compute for the empty table. Why this step? is defined as ; with there are literally zero items to average, so the average per bucket is . This is the smallest can ever be.
Step 2 — Expected unsuccessful search cost. Using the recap formula, expected cost . Why this step? The "" never disappears — even on an empty table you must compute the hash and touch the (empty) bucket once to discover it's empty. Search is never free; it is , not .
Step 3 — Insert . Key becomes the head of bucket 's chain. Now , so . Why this step? This is the base case of everything: one hash, one prepend, work, and ticks up by .
Example 2 — Light table, no collisions (C2)
Step 1 — Hash each key. Why this step? For , the bucket is just the last digit. Four distinct last digits → four distinct buckets.
Step 2 — Place them. Buckets each hold exactly one key; buckets are empty.

Figure s01: a vertical column of buckets (numbered –, top to bottom). Four of them — buckets , , , — each show a single green box holding their one key (the key equals the slot number here); the other six buckets are empty rectangles. The picture makes the "one key per occupied bucket, no chains longer than " situation obvious at a glance.
Step 3 — Load factor and longest chain. Why this step? means "on average items per bucket" — but average hides the truth here: no bucket exceeds length . This is the happy case chaining is designed to make common.
Example 3 — Collisions form a chain (C3)
Step 1 — Hash each key. Why this step? All four are (they differ by multiples of ), so all four collide into bucket . The hash cannot tell them apart by slot.
Step 2 — Build the chain (prepend at head). Insert order ; each new key goes to the front: Why this step? Prepend is — no walking to the tail. The chain reads newest-first.

Figure s02: the same -bucket column. Buckets , , are empty rectangles; bucket has a horizontal row of four red boxes joined by white arrows, reading from the head. A red caption underlines "length 4" — one bucket carrying the entire table while three sit idle.
Step 3 — Chain length and . Bucket has length ; all other buckets empty. . Why this step? Note says "average per bucket," yet reality is one bucket of and three of . Average is not maximum — a crucial lesson chaining teaches.
Example 4 — Exactly at the resize threshold (C4)
Step 1 — Check the threshold. Inserting key would make , so would become . Why this step? The rule fires on the would-be after the insert, not before. At exactly we're still fine; the insert that exceeds it forces the grow.
Step 2 — Double the array. Recall is the new bucket count after doubling: Why this step? Doubling (not adding a constant) is what makes resizes exponentially rare and keeps amortized insert — see Example 7.
Step 3 — Rehash all four keys with . So: bucket : ; bucket : . The old length-4 chain split into two length-2 chains.

Figure s03: now an -bucket column (slots –). Bucket holds two blue boxes ; bucket holds two yellow boxes ; every other bucket is empty. A green caption reads "resize m=4 → 8: long chain SPLITS," making visible how the single overloaded bucket of Figure s02 fans out into two half-length chains.
Step 4 — New load factor. Why this step? Doubling roughly halves , buying us room before the next resize. The chains got flatter exactly as promised.
Example 5 — Heavy table and wasteful table (C5)
Step 1 — Case (a), heavy: . Why this step? means chains average nodes. Chaining survives (unlike open addressing) — it just slows to touches per search. Graceful, but slow.
Step 2 — Case (b), oversized: . Why this step? Fast searches ( touches) — but buckets hold only items, so slots sit empty, wasting memory and hurting cache locality.
Step 3 — Verdict. Neither extreme is ideal. Keep near a constant like : fast and memory-lean. Why this step? This is the whole tuning philosophy — is the knob trading time against space.
Example 6 — The adversarial worst case (C6)
Step 1 — Hash the adversarial keys. Every multiple of hashes to bucket .

Figure s04: the -bucket column with buckets – all empty and bucket carrying a long row of six red boxes chained by white arrows. Two captions call it out: "attacker: all multiples of 8 → bucket 0" and "one chain of length n → worst case O(n)." Visually it's the exact opposite of the even spread in Figure s01.
Step 2 — Load factor at . Why this step? Here looks healthy (, under threshold!) yet the table is pathological. measures the average, and the average is blind to this all-in-one-bucket disaster.
Step 3 — Worst-case search cost.
search(48): hash to bucket , then walk the chain of all keys until is found (or the end for an unsuccessful search).
Why this step? The "expected " promise assumed simple uniform hashing — keys spread evenly. An adversary who breaks that assumption forces all into one chain, collapsing to .
Step 4 — The fix. Use a good or randomized hash so an attacker cannot predict which keys collide. Why this step? You cannot make worst case impossible (pigeonhole guarantees some collisions), but you can make the all-collide case astronomically unlikely.
Example 7 — Amortized cost of many inserts (C7)
Step 1 — List the resize points. As climbs, the array doubles at . At each doubling we copy every current key into the new array. The copy counts are the sizes just before each double: . Why this step? Rehashing touches all current keys — that's the cost per resize we must sum.
Step 2 — Sum the geometric series. More generally (or counting the final table build). Why this step? A geometric series is dominated by its last term. The total is linear in , not quadratic — this is the magic of doubling.
Step 3 — Amortize. Why this step? Spread the occasional expensive resize over all the cheap inserts and each insert averages — even though one individual insert (the one that resizes) costs .
Step 4 — Contrast with "add a constant." If instead we grew by each time, copies would be → per insert. Terrible. Why this step? This is why we double: geometric growth ( total) beats arithmetic growth ( total).
Example 8 — Real-world word problem (C8)
Step 1 — Identify and . sessions (items stored), buckets. Why this step? Word problems are just in disguise. Nail down which quantity is which before touching arithmetic.
Step 2 — Load factor and current cost. Since , they are within budget. ✔ Why this step? The expected cost formula (our recap) turns an abstract into a concrete "node-touches" number we can compare against the -touch goal.
Step 3 — Usage triples, same . Budget blown — chains average nodes. Why this step? scales linearly with when is fixed; tripling triples (from to ).
Step 4 — Fix: resize. To pull back to we need buckets — exactly the original. In doubling steps: ; at , . ✔ Why this step? Resizing restores the load factor and thus the speed — the same doubling policy from Example 4, now on a production scale.
Example 9 — Exam twist: successful vs unsuccessful search (C9)
Step 1 — Unsuccessful search. You must scan the entire chain (the key isn't there), so Why this step? Absent key ⇒ no early stop ⇒ you walk the whole expected-length- chain, plus the to hash. This is exactly our recap formula.
Step 2 — Successful search (careful formula). When the key is present you stop early, on average halfway down its chain. The standard formula is : Why this step? A present key lets you stop early, so you save roughly versus the unsuccessful case. The tiny term corrects for the key you're searching contributing to its own chain length.
Step 3 — Compare. Successful search is cheaper — you stop as soon as you hit the target instead of running off the end. Why this step? This matches intuition: finding something present lets you halt early; proving something absent forces a full scan.
Matrix coverage check
Recall Did we hit every cell?
C1 → Ex 1 (empty, single). C2 → Ex 2 (light, no collision). C3 → Ex 3 (chain forms). C4 → Ex 4 (resize boundary). C5 → Ex 5 (heavy + oversized). C6 → Ex 6 (adversarial ). C7 → Ex 7 (amortized doubling). C8 → Ex 8 (word problem). C9 → Ex 9 (successful vs unsuccessful). ✔ Every cell covered.
Connections
- Chaining — linked lists in buckets, load factor, resizing (index 3.3.3) — the parent this page drills into.
- Hash Functions — Example 6's fix (randomized hashing) lives here.
- Open Addressing — the alternative that dies at (contrast with Ex 5).
- Amortized Analysis — the formal backing for Example 7.
- Dynamic Arrays — same doubling series, applied to append.
- Pigeonhole Principle — why Example 6's collisions can never be fully avoided.
- Linked Lists — the bucket container walked in every search example.