DSA Notes
Master separate chaining for hash collision resolution — complete implementation using linked lists, array-backed lists, and balanced BSTs as chain structures, formal average-case analysis, Java HashMap
The Core Idea
In separate chaining, each slot in the hash table holds a separate collection (the "chain") of all key-value pairs that hash to that slot.
| Index 0 | [] |
| Index 1: [(Bob, 25) | (Carol, 35)] ← Two keys hashed to index 1 |
| Index 2 | [(Alice, 30)] |
| Index 3 | [] |
| Index 4 | [(Dave, 28)] |
| Index 5 | [] |
| Index 6: [(Eve, 22) | (Frank, 40)] |
The chain is most commonly a singly linked list, but any dynamic structure works.
Average-Case Analysis
Theorem (SUHA — Simple Uniform Hashing Assumption): If the hash function distributes keys uniformly, then for n keys in m buckets (α = n/m):
- Successful lookup: 1 + α/2 probes on average
- Unsuccessful lookup: 1 + α probes on average
Proof (informal):
For a successful lookup of key k:
- k is in the bucket containing k
- The bucket was built by n-1 other insertions (not k itself)
- Each of the n-1 other keys has probability 1/m of going into k's bucket
- Expected keys before k in the chain: ((n-1)/m) / 2 ≈ α/2
- Plus 1 for finding k itself: 1 + α/2
For α = 1 (n = m): average 1.5 comparisons per lookup — essentially O(1).
Implementation with Python List (Array-Backed Chain)
Python lists have O(1) amortized append and O(1) random access, which can be faster than linked list nodes for small chains due to better cache behavior:
Java HashMap's Treeification
Java's HashMap starts with linked list chains. When a single chain grows beyond 8 nodes, it converts that chain to a Red-Black Tree:
Chain length 1-7: Linked list, O(chain_length) lookup
Chain length ≥ 8: Red-Black tree, O(log(chain_length)) lookup
Why 8? Poisson distribution analysis shows:
P(chain length ≥ 8) ≈ 6×10⁻⁸ with good hash function
Only happens when hash function is poor or adversarial input existsThis gives Java HashMap O(log n) worst case instead of O(n) — important for security.
# Python equivalent: use SortedList or BST for large chains
from sortedcontainers import SortedList
class TreeifiedChaining:
TREE_THRESHOLD = 8
def __init__(self):
self.buckets = {} # Simplified: idx → list or SortedListChaining with a Sorted Chain
For chains that support range queries:
Performance Summary
| Operation | Chaining (α=0.75) | Chaining (α=2) | Chaining (worst) |
|---|---|---|---|
| Lookup | O(1) | O(1) | O(n) |
| Insert | O(1) | O(1) | O(n) |
| Delete | O(1) | O(1) | O(n) |
| Memory | O(n+m) | O(n+m) | O(n+m) |
Practical tip: With α ≤ 0.75 and a good hash function, every operation is effectively O(1) for all but adversarial inputs.
Summary
Separate chaining:
- Each slot stores a dynamic structure (linked list, array, BST)
- O(1) average for all operations when α ≤ 1
- Handles any load factor — just degrades gracefully
- Easy deletion — just remove from the chain
- Java HashMap uses linked lists → Red-Black trees when chains are long
Preferred over open addressing when:
- Deletion is frequent
- Load factor may exceed 0.7
- Worst-case O(n) is unacceptable (use treeified chains)
- Memory is not extremely tight
*Next Lesson: Open Addressing*
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Separate Chaining — Complete Implementation and Analysis.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Data Structures & Algorithms topic.
Search Terms
data-structures-algorithms, data structures & algorithms, data, structures, algorithms, hashing, chaining, separate chaining — complete implementation and analysis
Related Data Structures & Algorithms Topics