Skip to content

Commit 61f1aef

Browse files
Added Hashing and updated README
1 parent f8236af commit 61f1aef

15 files changed

+370
-18
lines changed
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

Hashing/README.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Hashing
2+
3+
As we know the collision issue that occurs with Hashing, I have resolved that issue using these Two techinques.
4+
5+
**1. Chaining:**
6+
The idea is to make each cell of hash table point to a linked list of records that have same hash function value. Chaining is simple, but requires additional memory outside the table.
7+
Code - [**Hashing using Chaining.**](hashingChaining.py)
8+
9+
**2. Open Addressing:**
10+
The idea here is to calculate a hash value(i.e. index position) and place the element there, if an element already exists at that index position we use one of the following strategies to encounter this problem:
11+
1. **Linear Probing:** Add 1 in the original index position and calculate the hash value again, and try placing the element in this position. If collision is encountered again, add 1 in this index. Repeat untill we find a place.
12+
2. **Quadratic Probing:** Add **i<sup>2</sup>** factor to the original index position and calculate the hash value again, and try placing the element in this position. Repeat untill we find a place.
13+
3. **Double Hashing:** Use 2 hashing functions. One for finding index position, another to calculate new index position if collision is encountered.
14+
15+
Code - [**Hashing with Collision Resolving Techniques.**](hashingStrategies.py)

Hashing/hashingChaining.py

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
from LinkedList.linkedlist import LinkedList
2+
import sys
3+
sys.path.append(".")
4+
5+
6+
class HashChain:
7+
'''
8+
Initialises hashtable size and hashtable with respective head nodes using LinkedList() class.
9+
'''
10+
11+
def __init__(self, hashsize=10) -> None:
12+
self._hashsize = hashsize
13+
self._hashtable = [0] * self._hashsize
14+
for i in range(self._hashsize):
15+
self._hashtable[i] = LinkedList()
16+
17+
def hashcode(self, key):
18+
'''
19+
Returns Hash value using simple Mod operator.
20+
'''
21+
return key % self._hashsize
22+
23+
def insert(self, element):
24+
'''
25+
Inserts element in hashtable.
26+
'''
27+
index = self.hashcode(element)
28+
self._hashtable[index].addSorted(element)
29+
30+
def search(self, key):
31+
'''
32+
Returns index position if the element is found in the table, else False.
33+
'''
34+
position = self.hashcode(key)
35+
return self._hashtable[position].search(key)
36+
37+
def display(self):
38+
'''
39+
Utility funtion to display Hashtable.
40+
'''
41+
for i in range(self._hashsize):
42+
print(f'[{i}] -- ', end='')
43+
self._hashtable[i].display()
44+
print()
45+
46+
47+
###############################################################################
48+
49+
50+
def options():
51+
'''
52+
Prints Menu for operations
53+
'''
54+
options_list = ['Insert Item', 'Search', 'Display Hashtable', 'Exit']
55+
56+
print("MENU")
57+
for i, option in enumerate(options_list):
58+
print(f'{i + 1}. {option}')
59+
60+
choice = int(input("Enter choice: "))
61+
return choice
62+
63+
64+
def switch_case(choice):
65+
'''
66+
Switch Case for operations
67+
'''
68+
if choice == 1:
69+
elem = int(input("Enter Item: "))
70+
H.insert(elem)
71+
print("Added Item.\n\n")
72+
73+
elif choice == 2:
74+
elem = int(input("Enter Item to search: "))
75+
result = H.search(elem)
76+
if result != -1:
77+
print(f'Found Element at {result}.')
78+
else:
79+
print('Item does not exist.')
80+
81+
elif choice == 3:
82+
print('HASHTABLE')
83+
H.display()
84+
85+
elif choice == 4:
86+
import sys
87+
sys.exit()
88+
89+
###############################################################################
90+
91+
92+
if __name__ == '__main__':
93+
H = HashChain(hashsize=10)
94+
while True:
95+
choice = options()
96+
switch_case(choice)

Hashing/hashingStrategies.py

+196
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
import os
2+
3+
4+
class HashLP:
5+
def randomPrime(self, upper):
6+
'''
7+
Generates a random prime number for hash_2 function.
8+
'''
9+
import random
10+
11+
prime = []
12+
for num in range(upper + 1):
13+
if num > 1:
14+
for i in range(2, num):
15+
if (num % i) == 0:
16+
break
17+
else:
18+
prime.append(num)
19+
20+
return random.choice(prime)
21+
22+
def __init__(self, hashsize=10) -> None:
23+
'''
24+
Initialises hashtable size and prime number.
25+
'''
26+
self._hashsize = hashsize
27+
self._hashtable = [-1] * self._hashsize
28+
self._size = 0
29+
self._q = self.randomPrime(self._hashsize)
30+
print(f'[ NOTE: Prime Number chosen: {self._q} ]')
31+
32+
def isfull(self):
33+
'''
34+
Returns True if Hash table is full, otherwise False.
35+
'''
36+
return self._size == self._hashsize
37+
38+
def isempty(self):
39+
'''
40+
Returns True if Hash table is empty, otherwise False.
41+
'''
42+
return self._size == 0
43+
44+
def hash_1(self, key):
45+
'''
46+
Returns Hash value using simple Mod operator.
47+
'''
48+
return key % self._hashsize
49+
50+
def hash_2(self, key):
51+
'''
52+
Returns Hash value using prime number.
53+
'''
54+
return self._q - (key % self._q)
55+
56+
def findnext(self, index_h1, index_h2, method='linear', factor=1):
57+
'''
58+
This function is used to calculate the next index position based on
59+
following parameters if the collision occurs.
60+
61+
{parameters} : 'index_h1' -- Hash value by hash_1 function
62+
'index_h2' -- Hash value by hash_2 function
63+
'linear' -- Linear Probing
64+
'quad' -- Quadratic Probing
65+
'double' -- Double Hashing
66+
67+
{returns} : Returns index when collison occurs.
68+
'''
69+
70+
if method == 'linear':
71+
return (index_h1 + factor) % self._hashsize
72+
elif method == 'quad':
73+
return (index_h1 + factor ** 2) % self._hashsize
74+
elif method == 'double':
75+
return (index_h1 + (factor * index_h2)) % self._hashsize
76+
77+
def insert(self, element, method='linear'):
78+
'''
79+
Inserts element in hashtable using the passed Method.
80+
'''
81+
if self.isfull():
82+
print('Hash Table is Full !')
83+
return False
84+
85+
position = index_h1 = self.hash_1(element)
86+
index_h2 = self.hash_2(element)
87+
88+
n = 0
89+
while self._hashtable[position] != -1:
90+
n += 1
91+
position = self.findnext(
92+
index_h1, index_h2, method=method, factor=n)
93+
94+
self._hashtable[position] = element
95+
self._size += 1
96+
return True
97+
98+
def search(self, key, method='linear'):
99+
'''
100+
Returns index position if the element is found in the table, else False.
101+
'''
102+
if self.isempty():
103+
print('Hashtable is empty')
104+
else:
105+
position = index_h1 = self.hash_1(key)
106+
index_h2 = self.hash_2(key)
107+
n = 0
108+
while True:
109+
if self._hashtable[position] == key:
110+
return position
111+
else:
112+
n += 1
113+
position = self.findnext(
114+
index_h1, index_h2, method=method, factor=n)
115+
if position == index_h1 - 1:
116+
break
117+
return
118+
119+
def display(self):
120+
'''
121+
Utility funtion to display Hashtable.
122+
'''
123+
if self.isempty():
124+
print('Hashtable is empty')
125+
else:
126+
for i, element in enumerate(self._hashtable):
127+
print(f'[{i}] -- {element}')
128+
129+
###############################################################################
130+
131+
132+
def method():
133+
'''
134+
Prints different methods for selecting a Hashing strategy.
135+
'''
136+
methods = ['Linear Probing', 'Quadratic Probing', 'Double Hashing']
137+
method_arg = ['linear', 'quad', 'double']
138+
139+
print("Chose a Method for collision case:")
140+
for i, method in enumerate(methods):
141+
print(f'{i + 1}. {method}')
142+
143+
method = int(input("Enter choice: "))
144+
method = method_arg[method - 1]
145+
146+
return method
147+
148+
149+
def options(method):
150+
'''
151+
Prints Menu for operations
152+
'''
153+
options_list = ['Insert Item', 'Search', 'Display Hashtable', 'Exit']
154+
155+
print(f"MENU for Hash Table using '{method}' strategy.")
156+
for i, option in enumerate(options_list):
157+
print(f'{i + 1}. {option}')
158+
159+
choice = int(input("Enter choice: "))
160+
return method, choice
161+
162+
163+
def switch_case(method, choice):
164+
'''
165+
Switch Case for operations
166+
'''
167+
if choice == 1:
168+
elem = int(input("Enter item: "))
169+
print("Added item.") if H.insert(
170+
elem, method=method) else print('Item cannot be added.')
171+
172+
elif choice == 2:
173+
elem = int(input("Enter item to search: "))
174+
result = H.search(elem, method=method)
175+
print(f'Found element at {result}.') if result != None else print(
176+
'Item does not exist.')
177+
178+
elif choice == 3:
179+
print('HASHTABLE')
180+
H.display()
181+
182+
elif choice == 4:
183+
import sys
184+
sys.exit()
185+
186+
###############################################################################
187+
188+
189+
if __name__ == '__main__':
190+
n = int(input('Enter hash table size: '))
191+
H = HashLP(hashsize=n)
192+
method = method()
193+
os.system('cls')
194+
while True:
195+
method, choice = options(method)
196+
switch_case(method, choice)
File renamed without changes.
6.39 KB
Binary file not shown.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)