From 41a315cf930c5a2bbbca532dd061bff2b0be266b Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 29 Oct 2026 23:03:48 +0100 Subject: [PATCH] U7 --- u7/hash_table.py | 108 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 u7/hash_table.py diff --git a/u7/hash_table.py b/u7/hash_table.py new file mode 100644 index 0000000..b3c2a5c --- /dev/null +++ b/u7/hash_table.py @@ -0,0 +1,108 @@ +class HashTable: + def __init__(self, capacity=10): + if type(capacity) is not int or isinstance(capacity, bool): + raise TypeError() + if capacity <= 0: + raise ValueError() + self._capacity = capacity + self.empty = object() + self.deleted = object() + self.slots = [self.empty] * capacity + self._size = 0 + + @property + def capacity(self): + return self._capacity + + def hash(self, key): + if not isinstance(key, str): + raise TypeError() + h = 0 + for ch in key: + h = (31 * h + ord(ch)) % self._capacity + return h + + def probe(self, key): + if not isinstance(key, str): + raise TypeError() + start = self.hash(key) + first_deleted = None + for step in range(self._capacity): + curr = (start + step) % self._capacity + item = self.slots[curr] + if item is self.empty: + return first_deleted if first_deleted is not None else curr + elif item is self.deleted: + if first_deleted is None: + first_deleted = curr + elif item[0] == key: + return curr + if first_deleted is not None: + return first_deleted + raise RuntimeError() + + def load_factor(self): + return self._size / self._capacity + + def __getitem__(self, key): + try: + pos = self.probe(key) + except RuntimeError: + raise KeyError(key) + item = self.slots[pos] + if isinstance(item, tuple) and item[0] == key: + return item[1] + raise KeyError(key) + + def __setitem__(self, key, value): + try: + pos = self.probe(key) + if isinstance(self.slots[pos], tuple) and self.slots[pos][0] == key: + self.slots[pos] = (key, value) + return + except RuntimeError: + pass + + if (self._size + 1) / self._capacity > 0.7: + old_slots = self.slots + self._capacity *= 2 + self.slots = [self.empty] * self._capacity + self._size = 0 + for item in old_slots: + if isinstance(item, tuple): + pos = self.probe(item[0]) + self.slots[pos] = item + self._size += 1 + + pos = self.probe(key) + self.slots[pos] = (key, value) + self._size += 1 + + def __delitem__(self, key): + try: + pos = self.probe(key) + except RuntimeError: + raise KeyError(key) + item = self.slots[pos] + if isinstance(item, tuple) and item[0] == key: + self.slots[pos] = self.deleted + self._size -= 1 + return + raise KeyError(key) + + def __contains__(self, key): + try: + pos = self.probe(key) + except RuntimeError: + return False + item = self.slots[pos] + return isinstance(item, tuple) and item[0] == key + + def __len__(self): + return self._size + + def __iter__(self): + for item in self.slots: + if isinstance(item, tuple): + yield item[0] +