Linear structures and hashing · 11 / 53
Hash tables, collisions and load factor
Understand → trace → implement → justify
3 min reading · allow extra time for practiceHash functions map keys to integers; indexing maps those integers to buckets. Equal hashes do not imply equal keys, so equality must still be checked. Hashing is not encryption, and collisions must not destroy data.
Chaining stores a bucket collection. Open addressing searches a probe sequence using linear, quadratic or double hashing. Clearing a deleted slot as if it had never been occupied can break searches; tombstones or correct backshift deletion are needed. Load factor α=n/m affects probe costs and triggers rehashing.
With suitable distribution, bounded load and hashing assumptions, access is expected O(1), but worst-case O(n) is possible. First hashing a long string depends on key length. Consider hash-flooding for untrusted inputs; changing a stored mutable key's hash/equality can make it unreachable.
Trace collision handling by hand
With five buckets and h(k)=k mod 5, keys 2,7,12 all hash to bucket two. Chaining may need three comparisons. Linear probing can place them in slots 2,3,4. Marking slot three EMPTY after deleting seven makes a search for twelve stop early; a DELETED tombstone keeps the probe alive.
Chaining load factor α=n/m may exceed one; open addressing requires spare slots. Rehashing recomputes positions for the new capacity. Expected O(1) under distribution assumptions can coexist with O(n) worst-case collision behaviour. Hash randomisation and balanced-tree buckets provide model-specific defences.
Equality and hashing must agree: equal keys must have equal hashes. Mutating fields used in key equality can break lookup. A hash is not a unique identifier; compare keys to resolve collisions. Cryptographic hashing has different goals from dictionary hashing and is not itself a password-storage scheme.
Foundation: Trace insertion, lookup and deletion of 2,7,12. Intermediate: Include tombstones in a resizing policy. Advanced: Measure p95 latency under skew and adversarial inputs, and state the source of randomness behind an expected bound.
A worked trace
m=5 with h(k)=k mod5: 7 and12 collide at2. Linear probing places12 at3. Treating2 as never used after deleting7 can hide12.
Cost and assumptions
Expected O(1) for small fixed-cost keys; poor distribution O(n). Rehashing is O(n) once and can be amortised with suitable growth.
Executable example
Run with Python 3. Assertions check a small example; they do not constitute a general correctness proof. Some advanced examples are explicitly small models or reference oracles, not full production implementations.
def chain_insert(table, key, value):
bucket = table[key % len(table)]
for i, (k, _) in enumerate(bucket):
if k == key:
bucket[i] = (key, value)
return
bucket.append((key, value))
table = [[] for _ in range(5)]
chain_insert(table, 7, "A")
chain_insert(table, 12, "B")
assert len(table[2]) == 2TEST YOUR UNDERSTANDING
Your turn
Does α=0.5 guarantee worst-case O(1)?
Reveal the reasoning
No. All keys may collide in one bucket. Load factor measures overall occupancy, not distribution quality.
Take it further
- Write down the input contract and the invariant before changing the example.
- Add empty, boundary, duplicate and adversarial cases where they are relevant. Compare with a simple oracle.
- Derive the cost under the stated model; measure several input sizes and explain discrepancies.
Primary reading & lecture notes
Original explanations in this course; these references provide proofs and further reading. Source links may cover the broader module.
MIT 6.006 · Introduction to Algorithms ↗Pat Morin · Open Data Structures ↗