-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathhash_table_open_addressing.py
151 lines (117 loc) · 3.95 KB
/
hash_table_open_addressing.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
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
class Hash_Table:
"""
Hash-Table.
Collision resolution: open addressing.
Load factor: [0.25, 0.5]
"""
def __init__(self):
"""
Generates an empty hash-table.
"""
self.num = 0
self.size = 8
self.marked = 0
self.num_min = 1
self.size_min = 8
self.marked_max = 4
self.h1 = lambda k: k % self.size
self.h2 = lambda k: 1 + 2*(k % self.marked_max)
self.table = [None for _ in range(self.size)]
def probing_sequence(self, key):
"""
Generates a sequence of pairs (slot, element) according
to the probing sequence of key.
"""
slot = self.h1(key)
step = self.h2(key)
for access in range(self.size):
yield (slot, self.table[slot])
slot = self.h1(slot + step)
def find(self, key):
"""
Returns the pair (key, value), if key is present in
the hash-table, and None otherwise.
"""
for (slot, element) in self.probing_sequence(key):
if element == None or element[0] == key:
return element
return None
def insert(self, key, value):
"""
Inserts the pair (key, value), if key is not present
in the hash-table. Otherwise, updates the value of
the pair holding key.
"""
probing_sequence = self.probing_sequence(key)
for (slot, element) in probing_sequence:
if element == None:
if element == None:
self.num += 1
self.marked += 1
self.table[slot] = (key, value)
if self.marked > self.marked_max:
self.expand()
return
elif element == "D":
self.table[slot] = (key, value)
for (slot, element) in probing_sequence:
if element == None:
self.num += 1
return
elif element[0] == key:
self.table[slot] = "D"
return
return
elif element[0] == key:
self.table[slot][1] = value
return
def delete(self, key):
"""
Deletes the pair (key, value) from the hash-table.
"""
for (slot, element) in self.probing_sequence(key):
if element == None:
return
elif element[0] == key:
self.num -= 1
self.table[slot] = "D"
if self.num <= self.num_min and self.size > self.size_min:
self.contract()
return
def rehash(self):
"""
Rehashes all the elements in the hash-table.
"""
self.num = 0
self.marked = 0
table = self.table
self.table = [None for slot in range(self.size)]
for element in table:
if element and element != "D":
self.insert(*element)
def expand(self):
"""
Expands the hash-table doubling its size.
"""
self.size *= 2
self.num_min *= 2
self.marked_max *= 2
self.rehash()
def contract(self):
"""
Contracts the hash-table halving its size.
"""
self.size //= 2
self.num_min //= 2
self.marked_max //= 2
self.rehash()
def __repr__(self):
"""
Represents the hash-table.
"""
def showItem(item):
"""
Returns a string representing item.
"""
return "" if item == None else "DELETED" if item == "D" else item
return "\n".join(" {}: [{}]".format(key, showItem(item)) for (key, item) in enumerate(self.table))