3.3.3 · D5Hashing
Question bank — Chaining — linked lists in buckets, load factor, resizing
This bank targets the four misconception zones the parent note raised — worst case vs expected, the load factor knob, resizing math, and the myth — plus the boundary cases (empty table, single bucket, , adversarial hash) that the parent only hinted at.
The picture behind every trap
Everything below circles back to two facts, so anchor them visually first.

The doubling sum, spelled out
True or false — justify
Every prompt below is a claim. Decide true/false, then give the why.
A chained hash table guarantees lookup in the worst case.
False. is the expected cost under simple uniform hashing (SUH); if every key collides into one bucket the chain has length , so worst-case lookup is .
If the load factor is , the hash table is "full" and must reject inserts.
False. That's Open Addressing thinking. Chaining has no "full" — just means buckets average two items; it slows gracefully, it does not break.
Doubling and adding a fixed slots per resize both give amortized insert.
False. Only multiplicative growth works: doubling makes resizes exponentially rare, so the copy work is the geometric . Adding a constant forces a resize every inserts, giving total, i.e. per insert.
Choosing a very large up front makes every operation strictly better.
False. Tiny is fast but wastes memory and destroys cache locality; a mostly-empty array thrashes memory. You want near a constant, not near zero.
Under simple uniform hashing, the expected length of any fixed bucket equals .
True. SUH makes each of the keys land in that bucket with probability independently, so the expected count is .
Insert into a chain is only if we prepend at the head.
True (with a caveat). Prepending to the head is ; but if we must reject duplicates we first scan the chain, making it . Cheap insert assumes we skip the duplicate check.
Rehashing during a resize reuses each key's old bucket index.
False. The bucket index becomes with the new count , so almost every key can move. That recomputation is exactly what splits long chains apart (left panel of Figure s01: a tall coral chain would scatter across the doubled array).
If the hash function is perfect for the current keys, resizing is never needed.
False. Even a perfect spreads keys over slots; once grows past , and chains lengthen regardless of hash quality. You still resize to keep bounded.
Successful and unsuccessful searches have the same asymptotic cost.
True. Unsuccessful scans the whole chain (); successful stops at the target — on average about halfway, giving . Both are ; only the constant differs. (The correction term is derived in the "Why questions" section.)
The pigeonhole principle proves that some collision is unavoidable when .
True. With more possible keys in the universe than slots , at least two keys must map to the same slot — no hash function can dodge this, which is why chaining exists. See Pigeonhole Principle.
Spot the error
Each line contains a flawed statement. Name the flaw.
"Chaining has no collisions because each bucket is a separate list."
The list is the collision handler — items sharing a bucket already collided. Chaining doesn't prevent collisions; it stores them in the chain.
"Since insert is and delete is , chaining is fully ."
Delete is only after you find the node; finding it is a search costing . Delete is expected, not .
"We resize whenever exceeds , so can never go above ."
momentarily exceeds the threshold on the insert that triggers the resize; the resize then pulls it back down. The threshold is a trigger, not a hard ceiling maintained every instant.
"Total resize work is ."
That series is — it's the adding-a-constant cost. Doubling gives the geometric series . The student mixed up arithmetic and geometric sums.
"With a bad hash, average cost is still ."
The bound assumes simple uniform hashing. A bad violates that assumption; it can pile keys into one chain, giving even on average. See Hash Functions.
"Chaining wastes no memory because lists only grow as needed."
The array of head pointers is allocated regardless of how many keys exist, and every node carries pointer overhead. Chaining trades extra pointer memory for graceful degradation.
"Because we double , a single insert can be worst case."
The insert that triggers a resize does rehashing work — its worst-case single cost is . Only the amortized cost over many inserts is ; see Amortized Analysis.
Why questions
Answer the "why", not just the "what".
Why is chaining's cost written as rather than just ?
The "" covers "always compute and touch one bucket" — this work happens even when the bucket is empty (). Dropping it would wrongly say an empty-table lookup costs .
Why does the successful search carry the extra term?
Averaging over all stored keys, the -th inserted key sits after on average keys in its chain; averaging over gives . The tiny just corrects for the first key having no predecessors.
Why do we double instead of tripling or adding a constant?
Any constant multiplier (double, triple) gives a geometric series and amortized (the collapse above); the specific choice trades memory slack against resize frequency. Adding a constant is the one thing that fails — it gives .
Why does chaining tolerate while open addressing cannot?
Chaining stores keys outside the array in growable lists, so a bucket can hold unlimited items. Open addressing stores keys inside the array's slots, so once slots run out () there is nowhere to probe.
Why does resizing "flatten" long chains?
The new count redistributes keys across twice as many buckets via , so keys that shared a slot under often split into different slots under . Longer array, shorter average chain — the left panel of Figure s01 shows the tall coral chain that resizing would break apart.
Why is the "simple uniform hashing" assumption necessary for the claim?
SUH guarantees each key spreads independently and evenly, so expected chain length equals . Without it, a hash could correlate keys into one bucket and the expectation argument collapses.
Why is the longest chain (not ) when is a constant?
Throwing keys into bins, the chance a fixed bin gets keys is roughly ; setting and using solves to . So expected chain is , but the unluckiest bucket is a bit taller.
Why might a smaller still hurt real-world speed despite fewer comparisons?
A sparse, large array has poor cache locality — the CPU fetches mostly-empty cache lines. Fewer comparisons on paper can lose to more cache misses in practice.
Why do we say resizing is amortized rather than average?
Amortized is a worst-case guarantee spread over a sequence — every -insert run costs total, no probability involved. "Average" would depend on randomness; amortization is deterministic accounting. See Amortized Analysis and the same trick in Dynamic Arrays.
Edge cases
The boundaries the topic quietly invites.
What is the expected search cost when the table is empty (, so )?
: you still compute and check one (empty) bucket. The "" is exactly why an empty lookup isn't free-but-zero.
With a single bucket (), what does chaining degenerate into?
Every key hashes to bucket , so the table becomes one long linked list — search is . This is the worst-case collision scenario made structural.
An adversary knows your hash function and feeds keys that all map to one slot — what happens and what's the fix?
All keys form one chain, so every operation degrades to . The fix is a randomized hash chosen at runtime so the adversary cannot predict the target slot.
If you insert then immediately delete the same key repeatedly at the resize threshold, do you thrash resizes?
No — grow at but only shrink at a much lower threshold like . This gap (hysteresis) means a single insert/delete pair never crosses both boundaries, so you cannot oscillate resize/un-resize.
What exactly is the "lower threshold" that prevents shrink-thrashing, and why that value?
Shrink when falls below, say, (grow at ). Because grow-boundary and shrink-boundary are far apart, after either resize lands safely in the middle (–), so many operations must pass before the next resize — total work stays amortized .
What is the load factor right after allocating a fresh table of buckets with no keys?
. The array of head pointers exists but every chain is empty — memory allocated, zero keys stored.
Can the worst-case chain length exceed badly even under uniform hashing?
Yes — expectation is , but by chance one bucket can hold far more (the longest chain is about when is constant, from the balls-into-bins bound above). Expected-short does not mean uniformly-short.
If returns the same value for two equal keys but we allow duplicates, what does search return?
Both copies sit in the same chain; search finds the first match it reaches. Allowing duplicates means you may store and later find multiple identical entries.
Connections
- Parent — the source topic these traps are built from.
- Open Addressing — where the rule actually applies.
- Amortized Analysis — the deterministic accounting behind "amortized ".
- Dynamic Arrays — same doubling trap and fix.
- Hash Functions — the quality of that makes uniform hashing hold.
- Pigeonhole Principle — why collisions are unavoidable when .
- Linked Lists — what a bucket degenerates into.