Look up a key using a collision free hash function that maps a static key set to exactly n table positions.
Minimal perfect hashing is a static dictionary technique. It builds a hash function for a fixed set of keys so that every stored key maps to a unique integer in the range to .
Unlike ordinary perfect hashing, a minimal perfect hash uses exactly one table slot per key. Lookup computes the hash position, checks the stored key, and returns the associated value if the key matches.
Problem
Given a fixed key set with keys and a query key , return the associated value if .
Model
A minimal perfect hash function for is a function such that:
and for all distinct keys :
The table stores each key at:
Algorithm
minimal_perfect_hash_lookup(T, k):
i = h(k)
if i < 0 or i >= length(T):
return NOT_FOUND
if T[i].key == k:
return T[i].value
return NOT_FOUNDThe final key comparison is required because the hash function is collision free only for the stored set . A query key outside may still map to some valid position.
Example
Let:
A minimal perfect hash function might assign:
| key | index |
|---|---|
| cat | 2 |
| dog | 0 |
| fox | 3 |
| owl | 1 |
The table has exactly four positions:
| index | stored key |
|---|---|
| 0 | dog |
| 1 | owl |
| 2 | cat |
| 3 | fox |
Lookup for "cat":
- compute
- check table position 2
- key matches
- return the value
Lookup for "cow":
- compute
- check that position
- return not found if the stored key differs
Correctness
For every stored key , the minimal perfect hash function assigns a unique position in the table. Therefore, lookup for a stored key computes the exact position where that key was placed.
If the slot contains a different key, then the query key is outside , because no two stored keys share a position.
Complexity
| operation | time |
|---|---|
| lookup | |
| worst lookup |
Lookup uses a constant number of hash operations and table reads. Construction may be more expensive, but construction is outside the lookup operation.
Space
The value table has exactly slots. The hash function itself also requires auxiliary metadata, whose size depends on the construction method.
When to Use
Minimal perfect hashing is appropriate when:
- the key set is static
- memory efficiency matters
- lookup speed matters
- duplicate keys are not allowed
- rebuilds are acceptable when the key set changes
It is common in compilers, keyword tables, static dictionaries, routing tables, and read only indexes.
Implementation
class MinimalPerfectHashTable:
def __init__(self, table, hash_func):
self.table = table
self.hash_func = hash_func
def get(self, key):
i = self.hash_func(key)
if i < 0 or i >= len(self.table):
return None
k, v = self.table[i]
if k == key:
return v
return Nonetype Entry[K comparable, V any] struct {
Key K
Value V
}
type MinimalPerfectHashTable[K comparable, V any] struct {
Table []Entry[K, V]
Hash func(K) int
}
func (h *MinimalPerfectHashTable[K, V]) Get(key K) (V, bool) {
i := h.Hash(key)
if i < 0 || i >= len(h.Table) {
var zero V
return zero, false
}
e := h.Table[i]
if e.Key == key {
return e.Value, true
}
var zero V
return zero, false
}