Unit 5 - DSA
Unit 5 - DSA
Bucket:
The hash function h (key) is used to map several dictionary entries in the hash
table.
Each position of the hash table is called bucket.
Collision:
The situation where a newly inserted key maps to an already occupied slot in hash
table is called collision.
Collision is situation in which hash function returns the same address for more
than one record.
Advantages:
Simple to implement.
Hash table never fills up, we can always add more elements to chain.
Less sensitive to the hash function or load factors.
It is mostly used when it is unknown how many and how frequently keys may be
inserted or deleted.
Disadvantages:
Cache performance of chaining is not good as keys are stored using linked list.
Open addressing provides better cache performance as everything is stored in same
table.
Wastage of Space (Some Parts of hash table are never used).
If the chain becomes long, then search time can become O (n) in worst case.
Uses extra space for links.
2. OPEN ADDRESSING:
In open addressing, all elements are stored in the hash table itself. So at any
point, size of the table must be greater than or equal to the total number of keys.
Insert (k): Keep probing until an empty slot is found. Once an empty slot is
found, insert k.
Search (k): Keep probing until slot’s key doesn’t become equal to k or an empty
slot is reached.
Delete (k): Delete operation is interesting. If we simply delete a key, then search
may fail. So slots of deleted keys are marked specially as “deleted”.
Clustering: The main problem with linear probing is clustering, many consecutive
elements form groups and it starts taking time to find a free slot or to search an
element.
Program:
# Define the size of the hash table def display():
TABLE_SIZE = 7 # Display the elements in the hash table
# Initialize the hash table with None values print(“\nElements in the hash table
h = [None] * TABLE_SIZE are:”)
for i in range(TABLE_SIZE):
def insert():
print(f “At Index {i} \t value = {h[i]}”)
# Get the value to insert
print(“\n”)
key = int(input “Enter a value to insert
def main():
into hash table: ”))
while True:
hkey = key % TABLE_SIZE
print(“\nQUADRATIC PROBING”)
# Try to insert the key using quadratic print(“1. INSERT”)
probing print(“2. DISPLAY”)
for i in range(TABLE_SIZE): print(“3. FIND”)
index = (hkey + i * i) % TABLE_SIZE print(“4. EXIT”)
if h[index] is None:
opt = int(input(“Enter your choice: ”))
for i in range(TABLE_SIZE):
if opt == 1:
index = (hkey + i * i) % TABLE_SIZE
insert()
if h[index] == key:
elif opt == 2:
print(f “Value {key} is found at
display()
index {index}.”)
elif opt == 3:
break
find()
else:
elif opt == 4:
print(“\nValue is not found!”)
exit(0)
c. DOUBLE HASHING:
We use another hash function hash2 (x) and look for i*hash2 (x) slot in ith
rotation.
Let hash(x) be the slot index computed using hash function.
If slot hash (x) % S is full, then we try (hash (x) + 1*hash2 (x)) % S.
If (hash (x) + 1*hash2 (x)) % S is also full, then we try (hash (x) + 2*hash2 (x))
% S.
If (hash (x) + 2*hash2 (x)) % S is also full, then we try (hash (x) + 3*hash2 (x))
% S.
First hash function is typically hash1 (key) = key % TABLE_SIZE.
A popular second hash function is: hash2 (key) = PRIME – (key %
PRIME) where PRIME is a prime smaller than the TABLE_SIZE.
A good second hash function is:
It must never evaluate to zero.
Must make sure that all cells can be probed.
Example:
Let us take hash function as “key mod 7” and sequence of keys as 50, 700, 76,
85, 92, 73, 101.