3.3.4 · D4Hashing

Exercises — Open addressing — linear probing, quadratic probing, double hashing

3,643 words17 min readBack to topic

Before we start, three reminders in plain words, each anchored to a picture of a row of numbered lockers (the table):

  • A table of size is a row of lockers numbered . Look at the chalk figure below — that is the whole universe we play in.
  • The base hash answers "which locker is key 's home?" It is just here — the remainder after dividing by , i.e. "how far past the last full lap of did we land." (See Hash functions — division & multiplication methods.)
  • A probe is one attempt: we look at a locker, and it is either empty (stop) or full (walk on by the rule).
Figure — Open addressing — linear probing, quadratic probing, double hashing

The at the end just means "if you walk off the right end of the locker row, wrap back to locker " — like a clock. We will lean on that wrap constantly.


Level 1 — Recognition

You are checking that you can read a formula and turn one crank of it.

Recall Solution L1.1

WHAT: we want — the remainder when is divided by . WHY : the locker row has only seats, so any key number must be folded down into . Division-remainder does exactly that fold. , so . Home locker is 3.

Recall Solution L1.2

Home: . That is probe — full. Recall the rule: "linear" means the offset , so from the home slot each next probe just adds . WHY : it is the simplest possible offset — walking one locker at a time guarantees that after steps you have touched every locker, so no free slot is ever skipped. Probe : , so — full. Probe : , so empty. Key lands in slot 8. Notice how linear probing just crawls , one locker at a time.

Recall Solution L1.3

Sequence: . The jumps get bigger — that is the whole point of the square.


Level 2 — Application

Now you run a full insertion sequence and keep the table state straight.

Recall Solution L2.1
  • → slot 1 (empty).
  • → taken; : → slot 2.
  • → taken, slot 2 taken; : → slot 3.
  • → 1,2,3 taken; : → slot 4. Final: index empty, , empty. A four-locker traffic jam (slots 1–4) formed from one home slot — primary clustering in the flesh.
Recall Solution L2.2

Step size: . Uh-oh — is a step of legal? We need coprime to (sharing no common factor > 1) so the probe sequence hits every slot. Since is prime, every value is coprime to , so step is fine. Probe : — empty (assume). Key slot 2. Here double hashing happened to behave like linear (step ), but that is a coincidence of this one key; a different key would get a different step.

Recall Solution L2.3

(home, full). . Probe : → slot 4. Compare with above: same home (slot 1) but step vs step different paths. That divergence is exactly how double hashing dodges secondary clustering.


Level 3 — Analysis

Now you reason about behaviour, not just crank arithmetic.

Recall Solution L3.1

Load factor — "the table is 75% full." WHY this formula: under uniform hashing each probe hits an occupied slot with probability ; the expected count of probes before the first empty one is . So about 4 probes per failed lookup. (See Load factor and rehashing.)

Recall Solution L3.2

Distinct residues: — only 3 slots. The other 5 slots () are unreachable, so an insert can fail even though the table is mostly empty. WHY the bound (for prime ): take a prime and consider the probes . Claim: these first probes are all distinct. Suppose two of them collided, with . Then . Since is prime it must divide one factor. But and (both are below because ), so divides neither — contradiction. Hence the first probes land on different lockers. So as long as at most half the table is full (), those half-a-table's-worth of distinct probes cannot all be occupied — at least one is empty, and the insert must succeed. Above that counting argument breaks and an insert can spin without ever hitting a free reachable slot. (See Prime table sizes.)

Recall Solution L3.3

First, a word we need: the home range of a cluster is the set of home slots that would funnel a new key into that cluster — i.e. all the lockers whose home-slot value lands the key onto the cluster, so it then crawls to the cluster's tail. Now the reasoning: a cluster is a contiguous run of full lockers. Any key whose home lands on any of those occupied slots (or the single empty-looking slot just before the run's start, which under insertion still funnels in) crawls forward to the cluster's tail and extends it. So the cluster's home range has size about . Probability the next uniformly-random home falls in that range — proportional to . Bigger clusters swallow more keys ⇒ rich-get-richer ⇒ primary clustering.


Level 4 — Synthesis

Now you combine ideas — designing/comparing, not just computing.

Recall Solution L4.1

Start state: slot full, slot full, rest empty. Linear:

  • : home 1 full → : empty → 2.
  • : home 1 full, 2 full → : empty → 3.
  • : home 3 now full → : empty → 4. Linear result: keys pile at — one tight run. Quadratic ():
  • : home 1 full → : empty → 2.
  • : home 1 full, : full → : empty → 5.
  • : home 3 → : empty → 4. Quadratic result: keys at spread out, no 3-in-a-row jam. That is the point of the growing square jump.
Recall Solution L4.2

Solve . Min table size: . is already prime, so the smallest valid prime size is . Convenient. (Choosing prime sizes is discussed in Prime table sizes and enables Load factor and rehashing triggers when crosses .)

Recall Solution L4.3

Requirement: must be coprime to . Since , its only prime factor is , so "coprime to " simply means "odd." Concrete formula: — always odd, ranges over . Any odd step size and a power-of-two produce a full permutation. WHY an odd step reaches every slot: stepping by from any start visits every locker exactly once iff you can only return to the start after exactly steps, i.e. the smallest multiple of divisible by is — which happens exactly when and share no common factor. For the only factor to avoid is , so any odd works; an even would share the factor and cycle through only half (or fewer) of the lockers. Check with a value: : , (odd ✓, coprime to 16 ✓).


Level 5 — Mastery

Now you defend a full design against edge cases and delete correctly.

Recall Solution L5.1

Search (home ): probe → slot 3 is EMPTY → algorithm concludes " not present" and stops. BUG is sitting right next door in slot 4, but the trail was cut. Why the naive delete fails: search stops at the first EMPTY, because during insertion an EMPTY meant "nothing was ever placed beyond here." Deleting to EMPTY lies about that history. Tombstone fix: mark slot 3 as DELETED (a tombstone), not EMPTY. Now searching : probe slot 3 sees DELETEDkeep going → probe slot 4 → found . ✓ Inserts may overwrite a tombstone; searches pass through it. Too many tombstones ⇒ rehash (see Load factor and rehashing).

Recall Solution L5.2

(a)

  • : probes.
  • : probes. Ratio: slower for going from half-full to 90%-full. Justification: as climbs toward the denominator shrinks toward , so the cost grows without bound — a tiny move from to multiplies the cost tenfold. Resizing (doubling the table) when crosses, say, keeps every operation cheap. The curve below shows the explosion.
Figure — Open addressing — linear probing, quadratic probing, double hashing

(b) With every locker is full. The probe sequence is a permutation of the lockers, so the algorithm probes — exactly probes, all landing on full lockers. What stops the loop: the termination rule from the top of the page — "if you have probed times you have visited every locker in the table, so abort." Without that ceiling the counter would keep incrementing and the probe sequence would just revisit lockers forever (an infinite loop). With it, insert into a full table cleanly fails after probes and signals "resize me." This is why we never let actually reach — we resize well before.

Recall Solution L5.3

(a) Scheme — double hashing. It is the only one of the three that kills both primary clustering (linear's crawl builds long runs) and secondary clustering (quadratic's fixed path is shared by all same-home keys): under double hashing two keys must agree on both and to walk the same path, which is very rare. (b) Table size. Need . Pick the next prime, , so any is coprime to (guarantees a full-permutation probe sequence with no divisibility worries) — see Prime table sizes. (c) Hashes. (division method, Hash functions — division & multiplication methods); so , never (no infinite loop) and always coprime to the prime . If keys may be adversarial, upgrade to a Universal hashing family so an attacker cannot force collisions. (d) Deletion. Use tombstones (DELETED): searches pass through them, inserts reuse them. This preserves probe chains (see L5.1). Track the tombstone count and rehash when tombstones dominate. (e) Resize trigger. When the live load factor crosses , rehash into a fresh table of the next prime . This keeps unsuccessful cost under 4 probes and preserves the contiguous-array Cache locality advantage over Hashing — chaining. Sanity check: at , , , and probes. ✓ The design meets the cost budget.