3.3.2 · D4Hashing

Exercises — Hash table — structure, open addressing vs chaining

2,664 words12 min readBack to topic

Before we start, let us pin down the two symbols used everywhere below, so no notation appears un-earned:


Level 1 — Recognition

L1.1 — Load factor

Problem. A hash table has capacity and currently stores keys. What is its load factor ? Would open addressing still be allowed to operate here?

Recall Solution

WHAT we did: plugged into the definition of load factor. WHY it matters: open addressing stores every key inside the array, so it needs at least one free slot — it only works while . Here , so it operates, but it is already above the usual rehash threshold (), so a good implementation would rehash to a bigger array right about now (see Load factor and dynamic resizing / rehashing).

L1.2 — Name the mechanism

Problem. In each scenario, name whether it describes chaining or open addressing: (a) Bucket 3 holds a linked list [19, 42, 8]. (b) The array is [_, _, 12, 22, 17] and 22 sits in slot 3 because slot 2 was taken.

Recall Solution

(a) Chaining — multiple keys hang outside the array in a list at one bucket. (See Linked lists.) (b) Open addressing — all keys live inside the flat array; 22 slid to the next slot by probing. Mnemonic: CHAIN out, PROBE in.


Level 2 — Application

L2.1 — Chaining insert & search count

Problem. With and , insert 9, 14, 24, 19, 3 in that order using separate chaining. Show every bucket's list. Then: how many list-nodes must a search for 24 examine?

Recall Solution

Compute each home slot (), appending to the tail of that bucket's list:

  • 9 % 5 = 4 → bucket 4: [9]
  • 14 % 5 = 4 → bucket 4: [9, 14] (collision → chain it)
  • 24 % 5 = 4 → bucket 4: [9, 14, 24]
  • 19 % 5 = 4 → bucket 4: [9, 14, 19]? No, append: [9, 14, 24, 19]
  • 3 % 5 = 3 → bucket 3: [3]

Final table:

Bucket List
0 []
1 []
2 []
3 [3]
4 [9, 14, 24, 19]

Search 24: go to bucket 4, scan the list front-to-back: 9 (no), 14 (no), 24 (yes) → examined 3 nodes.

Figure — Hash table — structure, open addressing vs chaining
WHY the whole search happens in one bucket: the hash sent us straight to bucket 4 in ; the only cost is walking the chain, whose expected length is (but here they all landed in one bucket — a worst case).

L2.2 — Linear probing insert

Problem. With and , insert 8, 15, 22 using linear probing (). Show the array after each insert and give the final array.

Recall Solution

Slot rule: , trying until empty.

  • 8 % 7 = 1 → slot 1 empty → place. [_,8,_,_,_,_,_]
  • 15 % 7 = 1 → slot 1 taken → : empty → place. [_,8,15,_,_,_,_] WHY slide right: nudges us one slot along.
  • 22 % 7 = 1 → slot 1 taken, slot 2 taken → : empty → place. [_,8,15,22,_,_,_]

Final: [_, 8, 15, 22, _, _, _] (indices 1,2,3 filled). This is a primary cluster — three keys in a contiguous run.

Figure — Hash table — structure, open addressing vs chaining

L2.3 — Polynomial string hash

Problem. Using the polynomial rolling hash with base and ASCII codes (, , ), compute , then its index into a table of capacity .

Recall Solution

Treat the string as a base- number, most significant character first: Compression (turn the huge integer into a valid slot): WHY base- and not a plain sum: the powers give each position a different weight, so "abc" and "cba" (an anagram) produce different codes — a plain sum would collide them. See Polynomial rolling hash & Rabin–Karp.


Level 3 — Analysis

L3.1 — Expected probes from

Problem. An open-addressed table sits at . Using the uniform-hashing model, how many probes does an unsuccessful search expect? Then: at what does that expectation reach exactly ?

Recall Solution

The model says each probed slot is occupied with probability , so the expected number of probes is the geometric sum At : For , solve

Figure — Hash table — structure, open addressing vs chaining
WHY it explodes near 1: the red curve rockets upward as because when nearly every slot is full, you keep hitting occupied slots before stumbling on the one hole.

L3.2 — Why the tombstone

Problem. Table [_, 8, 15, 22, _, _, _] (from L2.2, ). A student deletes 15 by simply blanking slot 2, giving [_, 8, _, 22, _, _, _]. Now search(22) is run. Trace it and explain the bug and the fix.

Recall Solution

search(22): . Probe:

  • : slot 1 holds 8 ≠ 22 → keep going.
  • : slot 2 is empty → search concludes "22 is not here" and stops. ✗

But 22 is in slot 3! The blanked slot 2 severed the probe chain — an empty slot is the universal "stop" signal. Fix: on deletion, write a tombstone (a DELETED marker) instead of a blank. Search treats a tombstone as "keep probing"; insertion treats it as "reusable free slot." With a tombstone in slot 2, search(22) correctly walks 1 → 2 (tombstone, continue) → 3 (found). ✓


Level 4 — Synthesis

L4.1 — Rehash trigger and reinsertion

Problem. An open-addressed table has and rehashes when . Keys are inserted one at a time. (a) After how many inserts does the first rehash trigger? (b) The rehash doubles capacity to ; after reinserting all keys, what is the new load factor?

Recall Solution

(a) Trigger condition: . The first integer crossing this is , giving . So the rehash fires on the 6th insert. (b) All keys are reinserted into the new array of capacity : WHY doubling: halving buys many cheap inserts before the next rehash, so the expensive copy happens rarely — the amortized cost per insert stays .

L4.2 — Choosing a strategy

Problem. You are building a symbol table for a compiler. Keys are identifier strings, and the workload is insert-heavy with frequent deletions and reinsertions as scopes open and close. You cannot predict the final key count. Argue for chaining or open addressing, citing three concrete properties.

Recall Solution

Choose separate chaining. Reasons, each tied to the workload:

  1. Frequent deletions → chaining deletes by simply unlinking a list node ( given the node), with no tombstones to accumulate and pollute the table. Open addressing would degrade under this churn (see L3.2 trap).
  2. Unknown final → chaining tolerates gracefully (lists just grow), so an under-sized array is only mildly slow, not broken. Open addressing fails at .
  3. Load-factor robustness → search stays instead of the sharper blow-up.

Trade-off acknowledged: chaining loses cache-friendliness (pointer chasing) — but for a correctness- and flexibility-driven compiler table that is an acceptable price. This is the CHAIN out, PROBE in decision applied deliberately. See Sets and Maps / Dictionaries.


Level 5 — Mastery

L5.1 — Collision probability (birthday flavour)

Problem. You hash keys uniformly into slots. Give the exact expression for the probability that at least two keys collide, and evaluate it (to 2 decimals) for .

Recall Solution

Compute the complement: the probability of no collision means all keys land in distinct slots. The 1st key is free; the 2nd must avoid 1 taken slot (); the -th must avoid taken slots: Therefore WHY this matters for hashing: with only 23 keys in 365 slots (, a nearly empty table) a collision is already more likely than not. This is the Birthday paradox — the reason collision resolution is mandatory, not a rare afterthought.

L5.2 — Prove tombstone-free deletion for chaining, and bound worst case

Problem. (a) Argue that chaining never needs tombstones. (b) Construct an adversarial input that forces a chained table with buckets into search, and state the load factor at that point.

Recall Solution

(a) In chaining, each bucket is a self-contained list. Deleting a key means unlinking its node; the list's other nodes remain reachable because the list's own pointers are repaired, not a global probe sequence. There is no "chain across the array" to sever — so no stop-signal ambiguity — so no tombstone is ever required. (b) Adversary: pick keys all congruent mod , e.g. for insert (all ). Every key lands in bucket 0, forming one list of length . Searching for the last key scans all nodes → .

  • Load factor at , : , yet the worst-case cost is not but the full list length . WHY: is an average over uniform hashing; a pathological hash (or a malicious key stream) defeats the average. The real defence is a good, unpredictable hash function — see Hash functions — properties and design.

Recall One-screen summary of every answer

L1.1: · L1.2: chaining / open addressing. L2.1: bucket 4 = [9,14,24,19], bucket 3 = [3], search 24 = 3 nodes · L2.2: [_,8,15,22,_,_,_] · L2.3: code , index . L3.1: probes; at · L3.2: tombstone fixes severed chain. L4.1: rehash on 6th insert; new · L4.2: chaining. L5.1: · L5.2: adversary all-same-bucket, , cost .