93 lines
3.0 KiB
Python
93 lines
3.0 KiB
Python
"""Hash tabuľka s lineárnym sondovaním a reťazcovými kľúčmi."""
|
||
|
||
|
||
class HashTable:
|
||
def __init__(self, capacity=10):
|
||
"""Vytvor prázdnu tabuľku s kladnou celočíselnou kapacitou."""
|
||
if not isinstance(capacity, int) or isinstance(capacity, bool): # бо булл по факту теж 1 або 0
|
||
raise TypeError("kapacita ma byt cele cislo")
|
||
if capacity <= 0:
|
||
raise ValueError("kapacita ma byt + a cela")
|
||
self.empty = object()
|
||
self.deleted = object()
|
||
self._capacity = capacity
|
||
self.size = 0
|
||
self.table = []
|
||
for i in range(capacity):
|
||
self.table.append(self.empty)
|
||
|
||
@property
|
||
def capacity(self):
|
||
"""Vráť aktuálny počet pozícií v poli."""
|
||
return self._capacity
|
||
|
||
def hash(self, key):
|
||
"""Vráť polynomiálny hash kľúča modulo aktuálna kapacita."""
|
||
if not isinstance(key, str):
|
||
raise TypeError("kluc ma byt retaz")
|
||
result = 0
|
||
for char in str(key):
|
||
result = result * 31 + ord(char)
|
||
return result % self.capacity
|
||
|
||
def probe(self, key):
|
||
"""Vráť index kľúča alebo miesta na vloženie bez zmeny tabuľky."""
|
||
if not isinstance(key, str):
|
||
raise TypeError("kluc ma byt retaz")
|
||
i = 0
|
||
del_slot = None
|
||
while i < self.capacity:
|
||
index = (self.hash(key) + i) % self.capacity
|
||
if self.table[index] is self.empty:
|
||
if del_slot is None:
|
||
return index
|
||
else:
|
||
return del_slot
|
||
elif self.table[index] is self.deleted:
|
||
if del_slot is None:
|
||
del_slot = index
|
||
|
||
elif self.table[index][0] == key:
|
||
return index
|
||
i += 1
|
||
if del_slot is not None:
|
||
return del_slot
|
||
else:
|
||
raise RuntimeError("tabula je povna")
|
||
#raise KeyError(key)
|
||
|
||
def load_factor(self):
|
||
"""Vráť podiel počtu aktívnych položiek a kapacity."""
|
||
return self.size / self.capacity if self._capacity > 0 else 0
|
||
|
||
def __getitem__(self, key):
|
||
index = self.probe(key)
|
||
return self.table[index][1]
|
||
|
||
def __setitem__(self, key, value):
|
||
index = self.probe(key)
|
||
if self.table[index] is self.empty:
|
||
self.size += 1
|
||
self.table[index] = (key, value)
|
||
|
||
def __delitem__(self, key):
|
||
index = self.probe(key)
|
||
if self.table[index] is self.empty or self.table[index] is self.deleted:
|
||
raise KeyError(key)
|
||
self.table[index] = self.deleted
|
||
self.size -= 1
|
||
|
||
def __contains__(self, key):
|
||
if self.table[self.probe(key)] is self.empty or self.table[self.probe(key)] is self.deleted:
|
||
return False
|
||
else:
|
||
return True
|
||
|
||
def __len__(self):
|
||
return self.size
|
||
|
||
def __iter__(self):
|
||
for bucket in self.table:
|
||
if bucket is not self.empty and bucket is not self.deleted:
|
||
yield bucket[0]
|