Hash Table
Map keys to values using a hash function for constant-time average lookups and inserts.
The Mathematics
Hash functions, collision resolution, and expected constant-time access
Hash Function
A hash function maps keys from a universe to bucket indices in :
A simple example: . The goal is to distribute keys uniformly across buckets.
Collisions
When for , a collision occurs. Since , collisions are inevitable (by the pigeonhole principle).
Chaining
Each bucket stores a linked list (chain) of all elements that hash to that index. Insert appends to the list; search scans the list:
Insert: — append to chain at
Search: expected — scan chain of expected length
Load Factor & Expected Complexity
The load factor is the average number of elements per bucket:
Under simple uniform hashing, the expected time for search is . If we keep by resizing when exceeds a threshold, all operations are expected (amortized for resizing).
See It Work
Inserting keys with h(k) = k mod 7 — watch for collisions and chaining
Empty hash table with 7 buckets. We use h(k) = k mod 7 with chaining for collisions.
The Code
Mapping hash table operations to a Python class with chaining
Mathematical Formulation
Create m empty buckets (linked lists for chaining)
Hash function maps key to a bucket index in [0, m)
Insert by appending to the chain at the hashed bucket
Search by scanning the chain at the hashed bucket
Load factor: ratio of elements to buckets. Expected O(1+α) search
Python Implementation
class HashTable:
def __init__(self, size=7):
self.size = size
self.buckets = [[] for _ in range(size)]
def _hash(self, key):
return key % self.size # Hash function
def insert(self, key):
idx = self._hash(key) # Compute bucket
self.buckets[idx].append(key) # Chain append
def search(self, key):
idx = self._hash(key) # Compute bucket
return key in self.buckets[idx] # Linear scan
def load_factor(self):
n = sum(len(b) for b in self.buckets)
return n / self.size # α = n/m