Level 4 — ApplicationHashing

Hashing

60 minutes50 marksprintable — key stays hidden on paper

Time limit: 60 minutes Total marks: 50 Instructions: Answer all questions. Show all working, including probe sequences, tables, and reasoning. No hints are provided.


Q1. Open addressing with mixed operations (12 marks)

You have a hash table of size m=11m = 11 using linear probing with hash function h(k)=kmod11h(k) = k \bmod 11.

Insert the following keys in order: 22,8,33,44,19,3022, 8, 33, 44, 19, 30.

(a) Show the final table (index 0–10) with the key stored at each index. (6 marks)

(b) Now delete key 3333 using a tombstone marker, then search for key 4444. State the exact sequence of indices probed during the search for 4444, and explain why the tombstone is required for correctness rather than simply blanking the slot. (6 marks)


Q2. Double hashing probe sequence (10 marks)

A table of size m=13m = 13 uses double hashing with h1(k)=kmod13,h2(k)=1+(kmod11).h_1(k) = k \bmod 13, \qquad h_2(k) = 1 + (k \bmod 11).

Key k=100k = 100 is inserted into a table where slots 99 and 33 are already occupied (all others empty).

(a) Compute the full probe sequence for inserting k=100k = 100 until an empty slot is found. Give the index of every probe. (7 marks)

(b) Explain why h2(k)h_2(k) is deliberately never allowed to be 00, and why choosing mm prime helps double hashing. (3 marks)


Q3. Load factor, resizing and amortized cost (12 marks)

A chaining hash table starts with capacity C=4C = 4 and doubles capacity whenever the load factor α\alpha would exceed 0.750.75 after an insertion. Each resize rehashes all existing elements. Insertions are done one at a time starting from empty.

(a) State the capacity of the table immediately after inserting the 1st,3rd,4th,7th1^{st}, 3^{rd}, 4^{th}, 7^{th} and 13th13^{th} elements. (5 marks)

(b) Consider inserting nn elements into an initially empty table (capacity 4, doubling policy). Show that the total work done, including all rehashing, is O(n)O(n), and hence the amortized cost per insertion is O(1)O(1). Give the geometric-series argument explicitly. (7 marks)


Q4. Universal hashing guarantee (8 marks)

Let H\mathcal{H} be a universal family of hash functions mapping a universe UU into {0,1,,m1}\{0,1,\dots,m-1\}.

(a) State the defining property of a universal family (the collision-probability bound). (2 marks)

(b) We choose hh uniformly at random from H\mathcal{H} and insert nn distinct keys into a table of size m=nm = n using chaining. Let XX be the number of keys that collide with a fixed key xx (i.e. hash to the same slot as xx, excluding xx itself). Prove that E[X]<1\mathbb{E}[X] < 1, and hence the expected search time for xx is O(1)O(1). (6 marks)


Q5. Applications — design problem (8 marks)

You are given an array of nn integers and a target TT. You must return all distinct unordered pairs (a,b)(a,b) with a+b=Ta+b = T.

(a) Design an O(n)O(n) average-time algorithm using a hash structure. Give clear pseudocode and explain how you avoid (i) duplicate pairs and (ii) reusing the same element twice when T=2aT = 2a. (5 marks)

(b) State the average and worst-case time complexity, and explain the single realistic condition under which the worst case occurs. (3 marks)

Answer keyMark scheme & solutions

Q1 (12 marks)

(a) h(k)=kmod11h(k)=k\bmod 11. Insert order 22,8,33,44,19,3022,8,33,44,19,30:

  • 22022 \to 0 (empty) → index 0
  • 888 \to 8 (empty) → index 8
  • 33033 \to 0 (occupied by 22) → probe 1 → index 1
  • 44044 \to 0 (occ), 1 (occ 33) → probe 2 → index 2
  • 19819 \to 8 (occ), 9 (empty) → index 9
  • 30830 \to 8(occ),9(occ),10 (empty) → index 10

Final table: (6 marks — 1 per correct placement)

idx 0 1 2 3 4 5 6 7 8 9 10
key 22 33 44 8 19 30

(b) Delete 3333 at index 1 → replace with tombstone (DEL marker). (2)

Search for 4444: h(44)=0h(44)=0.

  • probe index 0 → key 22 ≠ 44, continue
  • probe index 1 → tombstone, must continue (do NOT stop)
  • probe index 2 → key 44 found. ✓

Probe indices: 0, 1, 2. (2)

Why tombstone (2): If we simply blanked slot 1, the search for 4444 would hit an empty slot at index 1 and conclude 4444 is absent — but 4444 lives at index 2 because it was placed there by probing past the old key 3333. The tombstone preserves the probe chain: it tells search "keep going," while telling insert "you may reuse this slot."


Q2 (10 marks)

(a) h1(100)=100mod13h_1(100)=100\bmod 13. 137=9113\cdot7=91, 10091=9100-91=9 → start at 9. h2(100)=1+(100mod11)h_2(100)=1+(100\bmod 11). 119=9911\cdot9=99, 10099=1100-99=1 → step =1+1=2=1+1=2.

Probe sequence: (9+2i)mod13(9 + 2i)\bmod 13:

  • i=0i=0: 9 → occupied
  • i=1i=1: 11 → empty → insert at 11

Wait — check: slot 9 occupied (given), slot 11 empty → inserted at 11.

Probe indices computed: 9, 11. Since 11 is empty, insertion stops. (Full sequence would be 9, 11, 0, 2, 4, 6, 8, 10, 12, 1, 3, 5, 7.)

Marks: correct h1=9h_1=9 (2), correct h2=2h_2=2 (3), correct final placement at 11 (2).

(b) (3) h2h_2 must never be 00 because a step size of 00 makes the probe sequence stay on the same slot forever — an infinite loop that never explores the table. Choosing mm prime ensures gcd(step,m)=1\gcd(\text{step}, m)=1 for every allowed step, so the probe sequence (h1+ih2)modm(h_1 + i\cdot h_2)\bmod m visits all mm slots before repeating — guaranteeing an empty slot is found if one exists.


Q3 (12 marks)

(a) Policy: after insertion, if α=n/C>0.75\alpha = n/C > 0.75, double CC. Threshold at C=4C=4 is 33 (since 3/4=0.753/4=0.75 ok, 4/4>0.754/4>0.75). So resize triggers when count exceeds 0.75C\lfloor 0.75C\rfloor.

  • After 1st insert: 1/4=0.251/4=0.25C=4C=4
  • After 3rd insert: 3/4=0.753/4=0.75 (not >>) → C=4C=4
  • After 4th insert: 4/4=1.0>0.754/4=1.0>0.75 → double → C=8C=8
  • After 7th insert: 7/8=0.875>0.757/8=0.875>0.75 → double → C=16C=16
  • After 13th insert: 13/16=0.8125>0.7513/16=0.8125>0.75 → double → C=32C=32

Answers: 4, 4, 8, 16, 32. (1 each)

(b) (7) Ordinary insertions each cost O(1)O(1): nn insertions cost O(n)O(n) total. Resizes occur when the table doubles: at capacities 4,8,16,4,8,16,\dots A resize at capacity CC rehashes C\approx C elements (cost Θ(C)\Theta(C)). The capacities at which resizes happen form a geometric sequence up to the final capacity 2n\le 2n. Total rehashing work: jCj4+8+16++2n2(2n)=4n=O(n).\sum_{j} C_j \le 4 + 8 + 16 + \dots + 2n \le 2\cdot(2n) = 4n = O(n). Explicitly, i=0k42i=4(2k+11)<82k\sum_{i=0}^{k} 4\cdot 2^i = 4(2^{k+1}-1) < 8\cdot 2^{k}, and the largest term 2n\le 2n, so the sum <4(2n)=O(n)< 4\cdot(2n)=O(n). Total work =O(n)(inserts)+O(n)(rehashing)=O(n)= O(n)\text{(inserts)} + O(n)\text{(rehashing)} = O(n). Amortized per insertion =O(n)/n=O(1)= O(n)/n = O(1). ∎

Marks: inserts O(n) (1), resize cost Θ(C) (2), geometric sum bounded by O(n) (3), conclude amortized O(1) (1).


Q4 (8 marks)

(a) (2) H\mathcal{H} is universal if for all distinct xyUx\neq y \in U: PrhH[h(x)=h(y)]1m.\Pr_{h\in\mathcal H}[h(x)=h(y)] \le \frac{1}{m}.

(b) (6) Fix key xx. Define indicator Xy=1X_y = 1 if h(y)=h(x)h(y)=h(x), for each of the other n1n-1 keys yxy\neq x. Then X=yxXyX=\sum_{y\neq x} X_y. By universality E[Xy]=Pr[h(y)=h(x)]1/m\mathbb{E}[X_y]=\Pr[h(y)=h(x)] \le 1/m. (2) By linearity of expectation: E[X]=yxE[Xy]n1m.\mathbb{E}[X] = \sum_{y\neq x}\mathbb{E}[X_y] \le \frac{n-1}{m}. (2) With m=nm=n: E[X]n1n<1.\mathbb{E}[X] \le \frac{n-1}{n} < 1. (1) Expected search time for xx = time to scan its bucket =O(1+E[X])=O(1)= O(1 + \mathbb{E}[X]) = O(1). (1) ∎


Q5 (8 marks)

(a) (5) Use a hash set of seen values plus a result set of pairs.

found = set()          # values seen so far
pairs = set()          # canonical (min,max) tuples
for x in array:
    need = T - x
    if need in found:
        pairs.add( (min(x,need), max(x,need)) )
    found.add(x)
return pairs
  • Avoiding duplicate pairs (2): store each pair in canonical order (min,max) in a set, so (2,5) and (5,2) collapse and repeated occurrences don't re-add.
  • Avoiding element reuse when T=2aT=2a (2): because we only test need in found before adding the current x, a value aa pairs with another aa only if a previous aa was already inserted — i.e. two distinct array positions exist. A lone aa with need=aneed=a won't match itself. (1 for clean pseudocode)

(b) (3) Average time O(n)O(n) (each lookup/insert O(1)O(1) expected). Worst case O(n2)O(n^2) — occurs only when hashing degrades so that essentially all keys collide into one bucket (adversarial keys / bad hash function), making each set operation O(n)O(n). With a good/universal hash and random data this is negligible.


[
  {"claim":"Q1: linear probing final placements for 22,8,33,44,19,30 mod 11",
   "code":"m=11\nkeys=[22,8,33,44,19,30]\ntab=[None]*m\nfor k in keys:\n    i=k%m\n    while tab[i] is not None:\n        i=(i+1)%m\n    tab[i]=k\nresult = tab==[22,33,44,None,None,None,None,None,8,19,30]"},
  {"claim":"Q2: double hashing 100 into m=13 with slots 9,3 occupied lands at 11",
   "code":"m=13\nocc={9,3}\nh1=100%13\nstep=1+(100%11)\ni=0\nwhile ((h1+i*step)%m) in occ:\n    i+=1\nslot=(h1+i*step)%m\nresult = (h1==9 and step==2 and slot==11)"},
  {"claim":"Q3: capacities after inserts 1,3,4,7,13 with double-when->0.75 policy",
   "code":"def caps(n):\n    C=4;cnt=0;out={}\n    for _ in range(n):\n        cnt+=1\n        if cnt/C>0.75:\n            C*=2\n        out[cnt]=C\n    return out\nd=caps(13)\nresult = (d[1]==4 and d[3]==4 and d[4]==8 and d[7]==16 and d[13]==32)"},
  {"claim":"Q3: total rehash cost 4+8+16+...+2n is O(n); sum < 8n for n up to 1000",
   "code":"import math\nok=True\nfor n in range(4,1001):\n    total=0;C=4\n    while C<2*n:\n        total+=C\n        C*=2\n    ok = ok and (total < 8*n)\nresult = ok"},
  {"claim":"Q4: universal hashing expected collisions with m=n is < 1",
   "code":"n=symbols('n',positive=True)\nexpected=(n-1)/n\nresult = simplify(expected<1)==True or bool((expected.subs(n,1000))<1)"}
]