U7
This commit is contained in:
parent
1d83cc3f68
commit
41a315cf93
108
u7/hash_table.py
Normal file
108
u7/hash_table.py
Normal file
@ -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]
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user