-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhash_map.py
121 lines (93 loc) · 3.38 KB
/
hash_map.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"""
HashMap (Hash table)
Complexity:
Algorithm Average Worst case
Search O(1) O(n)
Insert O(1) O(n)
Delete O(1) O(n)
Sources: https://en.wikipedia.org/wiki/Hash_table
"""
from typing import Any, Iterable, List, Union
class HashMapItem:
def __init__(self, key: Union[str, int], value: Any) -> None:
self._key = key
self.value = value
@property
def key(self) -> Union[str, int]:
return self._key
def __repr__(self) -> str:
return f'<HashMapItem: ({self._key}: {self.value})>'
def __str__(self) -> str:
return f'({self._key}: {self.value})'
class HashMap:
def __init__(self, size: int) -> None:
self._size = size
self._table = [None] * size
def _hash_function(self, key: Union[str, int]) -> int:
_hash = 0
for i, c in enumerate(str(key)):
_hash += ord(c) * i
return _hash % self._size
def __getitem__(self, key: Union[str, int]) -> Any:
_initial_hash = _hash = self._hash_function(key)
while self._table[_hash] is not None:
if self._table[_hash] != -1:
if self._table[_hash].key == key:
return self._table[_hash].value
_hash += 1
_hash %= self._size
if _hash == _initial_hash:
break
raise KeyError(f'Key not found: {key}')
def __setitem__(self, key: Union[str, int], value: Any) -> None:
_initial_hash = _hash = self._hash_function(key)
while self._table[_hash] is not None and self._table[_hash] != -1:
if self._table[_hash].key == key:
self._table[_hash].value = value
return
_hash += 1
_hash %= self._size
if _hash == _initial_hash:
raise NotEnoughCells(
f'There is no place for this item: ({key}: {value})')
self._table[_hash] = HashMapItem(key, value)
def __delitem__(self, key: Union[str, int]) -> None:
_initial_hash = _hash = self._hash_function(key)
while self._table[_hash] is not None:
if self._table[_hash] != -1:
if self._table[_hash].key == key:
self._table[_hash] = -1
return
_hash += 1
_hash %= self._size
if _hash == _initial_hash:
break
raise KeyError(f'Key not found: {key}')
def __iter__(self) -> Iterable[HashMapItem]:
for item in self._table:
yield item
def __contains__(self, key: Union[str, int]) -> bool:
try:
self[key]
except KeyError:
return False
else:
return True
def expand(self, new_size: int) -> None:
if new_size <= self._size:
raise ValueError(
'"new_size" must be greater than the current size')
old_table = self._table[:]
self._size = new_size
self._table = [None] * self._size
self._transfer(old_table)
def _transfer(self,
old_table: List[Union[HashMapItem, None, int]]) -> None:
for item in old_table:
self[item.key] = item.value
def __repr__(self) -> str:
return f'<HashMap: {[str(_) for _ in self]}>'
def __str__(self) -> str:
return f'{[str(_) for _ in self]}'
class NotEnoughCells(Exception):
pass