class SimpleHashTable: def __init__(self): self.size = 10 self.table = [[] for _ in range(self.size)] def hash_function(self, key): return key % self.size def insert(self, key): index = self.hash_function(key) self.table[index].append(key) def __str__(self): result = [] for i, bucket in enumerate(self.table): if bucket: result.append(f"{i}: {bucket}") return ' | '.join(result) ht = SimpleHashTable() ht.insert(10) ht.insert(22) ht.insert(31) print(str(ht))
The hash function returns the remainder of the key divided by 10.
10 % 10 = 0, so 10 goes to bucket 0.
22 % 10 = 2, so 22 goes to bucket 2.
31 % 10 = 1, so 31 goes to bucket 1.
Thus, the printed state shows these buckets with their keys.
The remainder when dividing by 7 can be 0, 1, 2, 3, 4, 5, or 6.
So, the hash table needs 7 buckets indexed from 0 to 6.
class HashTable: def __init__(self, size): self.size = size self.table = [None] * size def hash_function(self, key): return key % self.size def insert(self, key): index = self.hash_function(key) if self.table[index] is None: self.table[index] = key else: self.table[index].append(key) ht = HashTable(5) ht.insert(10) ht.insert(15) print(ht.table)
The table is initialized with None values.
On first insert, the slot is set to an int key.
On second insert to the same slot, code tries to append to an int, which causes AttributeError.
class LinearProbingHashTable: def __init__(self): self.size = 10 self.table = [None] * self.size def hash_function(self, key): return key % self.size def insert(self, key): index = self.hash_function(key) start_index = index while self.table[index] is not None: index = (index + 1) % self.size if index == start_index: raise Exception('Hash table is full') self.table[index] = key def __str__(self): return str(self.table) ht = LinearProbingHashTable() ht.insert(5) ht.insert(15) ht.insert(25) print(ht)
5 % 10 = 5, placed at index 5.
15 % 10 = 5, index 5 occupied, move to 6.
25 % 10 = 5, indexes 5 and 6 occupied, move to 7.
So keys are at indexes 5, 6, and 7.
A good hash function spreads keys evenly across all buckets to reduce collisions.
Deterministic output is necessary but not enough.
Fast computation is good but less important than distribution.
Large hash values are not needed if distribution is uniform.