diff --git a/u7/hash_table.py b/u7/hash_table.py new file mode 100644 index 0000000..3d243d2 --- /dev/null +++ b/u7/hash_table.py @@ -0,0 +1,127 @@ +class HashTable: + def __init__(self, capacity=10): + if type(capacity) is not int or isinstance(capacity, bool): + raise TypeError("Kapacita musí byť celé číslo.") + if capacity <= 0: + raise ValueError("Kapacita musí byť kladné celé číslo.") + + self._capacity = capacity + self.empty = object() + self.deleted = object() + self.slots = [self.empty] * capacity + self.count = 0 + + @property + def capacity(self): + return self._capacity + + def hash(self, key): + if not isinstance(key, str): + raise TypeError("Kľúč musí byť reťazec.") + h = 0 + for znak in key: + h = (31 * h + ord(znak)) % self._capacity + return h + + def probe(self, key): + if not isinstance(key, str): + raise TypeError("Kľúč musí byť reťazec.") + + start_idx = self.hash(key) + first_deleted = None + + for krok in range(self._capacity): + idx = (start_idx + krok) % self._capacity + slot = self.slots[idx] + + if slot is self.empty: + return first_deleted if first_deleted is not None else idx + elif slot is self.deleted: + if first_deleted is None: + first_deleted = idx + elif slot[0] == key: + return idx + + if first_deleted is not None: + return first_deleted + raise RuntimeError("Tabuľka je plná a nemá žiadne voľné ani vymazané miesto.") + + def load_factor(self): + return self.count / self._capacity + + def __getitem__(self, key): + if not isinstance(key, str): + raise TypeError("Kľúč musí byť reťazec.") + idx = self.probe(key) + slot = self.slots[idx] + if slot is not self.empty and slot is not self.deleted and slot[0] == key: + return slot[1] + raise KeyError(key) + + def __setitem__(self, key, value): + if not isinstance(key, str): + raise TypeError("Kľúč musí byť reťazec.") + + start_idx = self.hash(key) + existing_idx = None + for krok in range(self._capacity): + idx = (start_idx + krok) % self._capacity + slot = self.slots[idx] + if slot is self.empty: + break + if slot is not self.deleted and slot[0] == key: + existing_idx = idx + break + + if existing_idx is not None: + self.slots[existing_idx] = (key, value) + return + + if (self.count + 1) / self._capacity > 0.7: + self._resize(self._capacity * 2) + + idx = self.probe(key) + self.slots[idx] = (key, value) + self.count += 1 + + def _resize(self, new_capacity): + old_slots = self.slots + self._capacity = new_capacity + self.slots = [self.empty] * new_capacity + self.count = 0 + + for slot in old_slots: + if slot is not self.empty and slot is not self.deleted: + k, v = slot + idx = self.probe(k) + self.slots[idx] = (k, v) + self.count += 1 + + def __delitem__(self, key): + if not isinstance(key, str): + raise TypeError("Kľúč musí byť reťazec.") + idx = self.probe(key) + slot = self.slots[idx] + if slot is not self.empty and slot is not self.deleted and slot[0] == key: + self.slots[idx] = self.deleted + self.count -= 1 + return + raise KeyError(key) + + def __contains__(self, key): + if not isinstance(key, str): + raise TypeError("Kľúč musí byť reťazec.") + try: + idx = self.probe(key) + except RuntimeError: + return False + slot = self.slots[idx] + return slot is not self.empty and slot is not self.deleted and slot[0] == key + + def __len__(self): + return self.count + + def __iter__(self): + for slot in self.slots: + if slot is not self.empty and slot is not self.deleted: + yield slot[0] \ No newline at end of file