-
Notifications
You must be signed in to change notification settings - Fork 5
/
hash_chain.py
executable file
·150 lines (118 loc) · 3.97 KB
/
hash_chain.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
"""
A hash chain is the successive application of a cryptographic hash function to a piece of data.
In computer security, a hash chain is a method to produce many one-time keys from a single key or password. [Wikipedia]
"""
class HashChain(object):
"""
Class HashChain realisation
Examples:
>>> hash_chain = HashChain(5)
>>> hash_chain.add("world")
>>> hash_chain.add("HellO")
>>> hash_chain.check(4)
HellO world
>>> hash_chain.find("World")
no
>>> hash_chain.find("world")
yes
>>> hash_chain.delete("world")
>>> hash_chain.check(4)
HellO
>>> hash_chain.delete("HellO")
>>> hash_chain.add("luck")
>>> hash_chain.add("GooD")
>>> hash_chain.check(2)
GooD luck
Explanation:
The ASCII code of ’w’ is 119, for ’o’ it is 111, for ’r’ it is 114,
for ’l’ it is 108, and for ’d’ it is 100. Thus, h("world") = 4.
It turns out that the hash value of “HellO“ is also 4.
We always insert in the beginning of the chain, so after adding
“world” and then “HellO” in the same chain index 4, first goes
“HellO” and then goes “world”. Of course, “World” is not found,
and “world” is found, because the strings are case-sensitive,
and the codes of ’W’ and ’w’ are different. After deleting “world”,
only “HellO” is found in the chain 4.
Similarly to “world” and “HellO”, after adding “luck” and
“GooD” to the same chain 2, first goes “GooD” and then “luck”.
"""
def __init__(self, bucket_count):
"""
Args:
bucket_count: max count of hash chain
"""
self._multiplier = 263
self._prime = 1000000007
self.bucket_count = bucket_count
self.elements = [[] for _ in range(0, bucket_count)]
def _hash_func(self, data):
"""
Hash function
Args:
data: text for hashing
Returns:
result of hash function
"""
ans = 0
for c in reversed(data):
ans = (ans * self._multiplier + ord(c)) % self._prime
return ans % self.bucket_count
@staticmethod
def _form_chain(chain):
"""
Function for formin chain
Args:
chain: text chain
"""
return ' '.join(chain)
def _check_data(self, data):
"""
Function for check data in hash table
Args:
data: string data
Returns:
return hash string and data
"""
hash_string = self._hash_func(data)
try:
ind = self.elements[hash_string].index(data)
except ValueError:
ind = -1
return hash_string, ind
def add(self, data):
"""
Add data to hash table
Args:
data: string data
"""
hash_string, ind = self._check_data(data)
if ind == -1:
self.elements[hash_string].append(data)
def find(self, data):
"""
Find data in hash table
Args:
data: string data
Returns:
True if found, False if not
"""
_, ind = self._check_data(data)
return ind != -1
def delete(self, data):
"""
Delete data from hash table
Args:
data: string data
"""
hash_string, ind = self._check_data(data)
if ind != -1:
self.elements[hash_string].pop(ind)
def check(self, idx):
"""
Check hash_chain by index
Args:
idx: index in hash
Returns:
String chain separated by space
"""
return self._form_chain(cur for cur in reversed(self.elements[idx]) if self._hash_func(cur) == idx)