class HashTable: _DELETED = object() def __init__(self, capacity=10): if type(capacity) is not int: raise TypeError("Capacity must be an integer") if capacity <= 0: raise ValueError("Capacity must be positive") self._capacity = capacity self._table = [None] * capacity self._size = 0 @property def capacity(self): return self._capacity def _validate_key(self, key): if not isinstance(key, str): raise TypeError("Key must be a string") def hash(self, key): self._validate_key(key) h = 0 for char in key: h = (31 * h + ord(char)) % self.capacity return h def probe(self, key): self._validate_key(key) start = self.hash(key) first_deleted = None for step in range(self.capacity): index = (start + step) % self.capacity item = self._table[index] if item is None: if first_deleted is not None: return first_deleted return index if item is self._DELETED: if first_deleted is None: first_deleted = index elif item[0] == key: return index if first_deleted is not None: return first_deleted raise RuntimeError("Hash table is full") def __setitem__(self, key, value): self._validate_key(key) index = self.probe(key) item = self._table[index] # Existujúci kľúč: prepíš hodnotu. if item is not None and item is not self._DELETED: if item[0] == key: self._table[index] = (key, value) return # Nový kľúč: skontroluj zaplnenie. if (self._size + 1) / self.capacity > 0.7: self._resize(self.capacity * 2) index = self.probe(key) self._table[index] = (key, value) self._size += 1 def __getitem__(self, key): self._validate_key(key) index = self.probe(key) item = self._table[index] if item is None or item is self._DELETED or item[0] != key: raise KeyError(key) return item[1] def __delitem__(self, key): self._validate_key(key) index = self.probe(key) item = self._table[index] if item is None or item is self._DELETED or item[0] != key: raise KeyError(key) self._table[index] = self._DELETED self._size -= 1 def __contains__(self, key): self._validate_key(key) index = self.probe(key) item = self._table[index] return ( item is not None and item is not self._DELETED and item[0] == key ) def __len__(self): return self._size def __iter__(self): for item in self._table: if item is not None and item is not self._DELETED: yield item[0] def load_factor(self): return self._size / self.capacity def _resize(self, new_capacity): old_table = self._table self._capacity = new_capacity self._table = [None] * new_capacity self._size = 0 for item in old_table: if item is not None and item is not self._DELETED: key, value = item index = self.probe(key) self._table[index] = (key, value) self._size += 1