Skip to main content

Hash Collisions: The Pigeonhole Principle in Practice

Easy

Interview Question: "What causes hash collisions, and how do separate chaining and open addressing resolve them? What are primary clustering and the tombstone problem in open addressing?"

The Quick Answer​

"A hash collision occurs when two distinct keys produce the exact same array index. By the Pigeonhole Principle, mapping an infinite universe of potential inputs into a finite number of array slots makes collisions mathematically inevitable. Data structures resolve them using either Separate Chaining (storing colliding items in linked lists or trees per bucket) or Open Addressing (probing for the next open slot in the array)."


Collision Resolution Strategies: Chaining vs. Open Addressing​

DimensionSeparate ChainingOpen Addressing
Storage ModelElements stored outside the array in linked nodes or trees.All elements stored directly inside the main array.
Max Load FactorCan exceed 1.01.0 (buckets hold multiple elements).Must remain strictly below 1.01.0 (typically resizes at 0.50.5–0.70.7).
Cache LocalityPoor (following pointer references causes CPU cache misses).Excellent (sequential array access maximizes CPU cache hits).
Language UsageJava HashMap, C++ std::unordered_map.Python dict, Ruby Hash.

Open Addressing Probing Techniques & Pitfalls​

When using open addressing, finding an alternate slot when index h(k)h(k) is occupied relies on a probing sequence h(k,i)h(k, i):

  1. Linear Probing (h(k)+ih(k) + i):
    • Checks sequential slots (+1,+2,+3…+1, +2, +3 \dots).
    • The Flaw (Primary Clustering): Occupied slots clump together into long contiguous blocks. Any key hashing into a cluster must traverse to the end of the cluster, severely degrading performance.
  2. Quadratic Probing (h(k)+c1i+c2i2h(k) + c_1 i + c_2 i^2):
    • Probes at quadratic intervals (+1,+4,+9…+1, +4, +9 \dots).
    • Solves primary clustering, but keys that hash to the exact same initial index follow the identical probe path (Secondary Clustering).
  3. Double Hashing (h1(k)+i⋅h2(k)h_1(k) + i \cdot h_2(k)):
    • Uses a second independent hash function h2(k)h_2(k) as the step size. Produces the most uniform distribution with virtually zero clustering.

The Interview Trap: The Tombstone Deletion Problem​

In open addressing, you cannot simply write null to delete a key.

  • Why? Consider key BB that collided with key AA and was placed into slot 5 via probing. If key AA at slot 4 is later deleted and set to null, a subsequent search for key BB will hash to slot 4, encounter null, conclude that key BB never existed, and abort early!
  • The Fix (Tombstones): Deleted slots are marked with a special sentinel value: DELETED (or tombstone). During searches, the algorithm continues probing past DELETED markers, but during insertions, it can overwrite DELETED slots with new data.

Clean Code Example​

Here is how collision strategies are utilized in standard language collections:

import java.util.HashMap;

// Java uses SEPARATE CHAINING (LinkedList -> Red-Black Tree)
public class CollisionDemo {
public static void main(String[] args) {
// Strings "Aa" and "BB" famously produce the identical Java hashCode: 2112
String key1 = "Aa";
String key2 = "BB";

System.out.println(key1.hashCode()); // 2112
System.out.println(key2.hashCode()); // 2112

HashMap<String, String> map = new HashMap<>();
map.put(key1, "First Value");
map.put(key2, "Second Value"); // Stored in the same bucket via separate chaining

System.out.println(map.get(key1)); // "First Value"
System.out.println(map.get(key2)); // "Second Value"
}
}