-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdynamic_hash.py
More file actions
153 lines (124 loc) · 4 KB
/
dynamic_hash.py
File metadata and controls
153 lines (124 loc) · 4 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
from tool_box.array import Array # import Array from array.py
import math
class HashNode:
def __init__(self, key, data):
self.key = key
self.data = data
self.next = None
class DynamicHash:
""" Open Addressing: Double Hashing """
def __init__(self):
self.array = Array()
self.table_size = 0
self.useful = 0
self.deleted_count = 0
def hash_1(self, key):
""" m * (a * key % 1) , 'a' is golden ratio , 'm' is table-size """
a = (math.sqrt(5) - 1) / 2
n = int(self.table_size * (a * key % 1))
return n
def hash_2(self, key):
n = 2 * int(key % self.table_size) + 1
return n
def key_to_int(self, key):
k = 0
for char in key:
k += ord(char)
return k
def hash_function(self, key, i):
key = self.key_to_int(key)
hash_1 = self.hash_1(key)
hash_2 = self.hash_2(key)
m = self.table_size
return (hash_1 + i * hash_2) % m
def is_full_threshold(self):
""" return True if n/m >= full threshold which is 0.75 """
n = self.useful
m = self.table_size
return n / m >= 0.75
def is_empty_threshold(self):
""" return True if n/m <= empty threshold which is 0.25 """
n = self.useful
m = self.table_size
return n / m <= 0.25
def rehashing(self, new_array):
m = len(self.array)
for item in self.array:
if item and item != "deleted":
for i in range(m):
index = self.hash_function(item.key, i)
if new_array[index] is None:
new_array[index] = item
break
return new_array
def expand(self):
m = self.table_size
if m == 0:
self.array = Array(1)
self.table_size = 1
return None
if self.is_full_threshold():
self.table_size *= 2
new_array = Array(self.table_size)
self.array = self.rehashing(new_array)
def insert(self, key, data):
self.expand()
m = self.table_size
array = self.array
for i in range(m):
index = self.hash_function(key, i)
if array[index] is None or array[index] == "deleted":
array[index] = HashNode(key, data)
self.useful += 1
return
def search(self, key):
m = self.table_size
arr = self.array
for i in range(m):
index = self.hash_function(key, i)
item = arr[index]
if item and item != "deleted":
if item.key == key:
return index
return None
def update(self, key, value):
index = self.search(key)
if index is not None:
item = self.array[index]
item.value = value
def delete(self, key):
index = self.search(key)
if index is not None:
self.array[index] = "deleted"
self.useful -= 1
self.deleted_count += 1
self.shrink()
def shrink(self):
if self.is_empty_threshold():
self.table_size //= 2
new_array = Array(self.table_size)
self.array = self.rehashing(new_array)
def get_item(self, key):
index = self.search(key)
if index is not None:
item = self.array[index]
return item.data
return None
def __len__(self):
return self.useful
def __setitem__(self, key, data):
self.insert(key=key, data=data)
def __getitem__(self, key):
return self.get_item(key)
def __delitem__(self, key):
self.delete(key)
def __contains__(self, key):
index = self.search(key)
if index is not None:
return True
else:
return False
def __iter__(self):
for item in self.array:
if item and item != "deleted":
yield item.key