forked from Dstar4/Hash-Tables
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhashtable.py
More file actions
166 lines (123 loc) · 3.92 KB
/
hashtable.py
File metadata and controls
166 lines (123 loc) · 3.92 KB
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# '''
# Linked List hash table key/value pair
# '''
from dynamic_array import dynamic_array
class LinkedPair:
def __init__(self, key, value):
self.key = key
self.value = value
self.next = None
class HashTable:
'''
A hash table that with `capacity` buckets
that accepts string keys
'''
def __init__(self, capacity):
self.capacity = capacity # Number of buckets in the hash table
self.storage = [None] * capacity
# _ means private function, should not be used outside of class, but you can
def _hash(self, key):
'''
Hash an arbitrary key and return an integer.
You may replace the Python hash with DJB2 as a stretch goal.
'''
x = hash(key)
print('x', x)
return x
# _hash(3,'8')
def _hash_djb2(self, key):
'''
Hash an arbitrary key using DJB2 hash
OPTIONAL STRETCH: Research and implement DJB2
'''
pass
def _hash_mod(self, key):
'''
Take an arbitrary key and return a valid integer index
within the storage capacity of the hash table.
'''
return self._hash(key) % self.capacity
# if self.capacity is not FULL:
# if self.capacity:
# current_next = self.next
# self.next = LinkedPair(value, self, current_next)
# else:
# self.key = key
# print('k',self.key)
# self.value = value
# print('v',self.value)
#
# print(insert(3, 3, 5))
def insert(self, key, value):
'''
Store the value with the given key.
Hash collisions should be handled with Linked List Chaining.
Fill this in.
'''
index = self._hash_mod(key)
if self.storage[index] is not None:
print(f"WARNING: Collusion has occured at {index}")
else:
self.storage[index] = (key, value)
return
def remove(self, key):
'''
Remove the value stored with the given key.
Print a warning if the key is not found.
Fill this in.
'''
index = self._hash_mod(key)
if self.storage[index] is not None:
if self.storage[index][0] == key:
self.storage[index] = None
else:
print(f"WARNING: Collusion has occured at {index}")
else:
print(f"Warning key ({key}) not found")
return
def retrieve(self, key):
'''
Retrieve the value stored with the given key.
Returns None if the key is not found.
Fill this in.
'''
index = self._hash_mod(key)
if self.storage[index] is not None:
if self.storage[index][0] == key:
return self.storage[index][1]
else:
print(f"WARNING: Collusion has occured at {index}")
else:
return None
return
def resize(self):
'''
Doubles the capacity of the hash table and
rehash all key/value pairs.
Fill this in.
'''
old_storage = self.storage
self.capacity *= 2
self.storage = [None] * self.capacity
for item in old_storage:
self.insert(item[0], item[1])
if __name__ == "__main__":
ht = HashTable(2)
ht.insert("line_1", "Tiny hash table")
ht.insert("line_2", "Filled beyond capacity")
ht.insert("line_3", "Linked list saves the day!")
print("")
# Test storing beyond capacity
print(ht.retrieve("line_1"))
print(ht.retrieve("line_2"))
print(ht.retrieve("line_3"))
# Test resizing
old_capacity = len(ht.storage)
ht.resize()
new_capacity = len(ht.storage)
print(f"\nResized from {old_capacity} to {new_capacity}.\n")
# Test if data intact after resizing
print(ht.retrieve("line_1"))
print(ht.retrieve("line_2"))
print(ht.retrieve("line_3"))
print("")