Resolve hash collisions by scanning sequential slots until the key is found or an empty slot appears.
Linear probing resolves collisions in an open addressing hash table by scanning forward one slot at a time. All keys are stored directly inside the table, and probing follows a contiguous sequence.
You search by computing the hash index and walking forward until you either find the key or reach an empty slot.
Problem
Given a hash table using linear probing and a key , return the associated value if it exists.
Model
- Table has size
- Hash function
- Probe sequence:
for
Algorithm
linear_probing_search(T, k):
i = h(k)
start = i
while T[i] is occupied:
if T[i].key == k:
return T[i].value
i = (i + 1) mod m
if i == start:
break
return NOT_FOUNDExample
Let:
Insert:
All hash to index , so they occupy:
| index | value |
|---|---|
| 3 | 10 |
| 4 | 17 |
| 5 | 24 |
Search for :
- start at index 3
- check 10, then 17, then 24
- match found
Correctness
Linear probing guarantees that every key is placed somewhere along its probe sequence. The lookup follows exactly the same sequence, so it will encounter the key if it exists.
An empty slot terminates the search, proving that the key does not exist.
Complexity
Let be the load factor.
| case | time |
|---|---|
| average | |
| worst |
Performance degrades as approaches 1 due to clustering.
Space
All elements are stored directly in the table.
When to Use
Linear probing is appropriate when:
- memory locality is important
- cache performance matters
- implementation simplicity is desired
It performs poorly under high load due to primary clustering.
Implementation
class HashTable:
def __init__(self, m=8):
self.m = m
self.table = [None] * m
def _hash(self, key):
return hash(key) % self.m
def get(self, key):
i = self._hash(key)
start = i
while self.table[i] is not None:
k, v = self.table[i]
if k == key:
return v
i = (i + 1) % self.m
if i == start:
break
return Nonetype Entry[K comparable, V any] struct {
Key K
Value V
Used bool
}
type HashTable[K comparable, V any] struct {
Table []Entry[K, V]
M int
}
func (h *HashTable[K, V]) hash(key K) int {
return int(uintptr(any(key))) % h.M
}
func (h *HashTable[K, V]) Get(key K) (V, bool) {
i := h.hash(key)
start := i
for h.Table[i].Used {
if h.Table[i].Key == key {
return h.Table[i].Value, true
}
i = (i + 1) % h.M
if i == start {
break
}
}
var zero V
return zero, false
}