DEV Community is a community of 700,142 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Hash Table data structure

Aya Bouchiha
Full stack web developer

Hi, this is #day_4, we are going to talk about hash tables

Definition of Hash table

"A hash table is a type of data structure that stores key-value pairs. The key is sent to a hash function that performs arithmetic operations on it. The result (commonly called the hash value or hash) is the index of the key-value pair in the hash table."

Application of hash tables

• File System
• Programming Language
• Rabin-Karp Algorithm
• School system
• Search Engines

Space and Time complexity

The space complexity of the hash table is O(n)

insert delete search
Average O(1) O(1) O(1)
Worst O(n) O(n) O(n)

Collision

Collision is when two keys or more result the same value after hashing them.
example:

Data:

Name ( key ) grade ( value )
aya 77
yaa 83

Hash function example

def hashKey(self,key) -> int:
"""
ord  -> built-in method that returns the Unicode code of a character
size -> the hash table length
using (hashedString % self.size) -> for not getting an index out of the range of our hash table length
"""
hashedString = 0
for character in key:
hashedString += ord(character)
return hashedString % self.size

Getting the hashed names ( hashed keys )

#! collision
print(table.hashKey('aya')) # 15
print(table.hashKey('yaa')) # 15

Solutions of the Collision problem

• Linear Probing : is inserting the value directly if the table[hashedKey] is empty else inserting It into the next value table[(key + 1) % sizeOfTheTable ] if it available Otherwise tring for the next index until finding an empty place more details...

• Quadratic Probing : operates by taking the original hash index and adding successive values of an arbitrary quadratic polynomial until an open slot is found more details...

• Double Hashing : is applying another hash function to keyhashTable[(hashfunc1(key) + i * hashfunc2(key)) % sizeOfTheTable]
more details...

2. Separate Chainings

This technique creates a linked list to the slot for which collision occurs and insert into the wanted value as a node which has three properties (key, value, next)more details...

Implementation of the hash table (separate chaining) using python

Although Hash table are built-in data structure in programming languages such as dictionary in python, Map in javascript, let's try to implement it in python.
if you are not familiar with python you can find the implementation of hash table in other langauges in these links:

class Node:
def __init__(self,key,value,next = None):
self.key = key
self.value = value
self.next = next

def __init__(self)    :
self.size = 0

def insertAtFirst(self,key,value):
self.size += 1

def insertAtLast(self,key,value):
while current.next:
current = current.next
current.next = Node(key,value)
self.size+=1

def remove(self, key):
previous = None
if current.key == key:
else:
while current.next:
previous = current
current = current.next
if current.key == key:
previous.next = current.next
self.size -= 1

def find(self, key):
while current:
if current.key == key:
return current.value
current = current.next

def printAll(self):
while current:
print(current.key,current.value)
current = current.next

Hash Table Class

class HashTable:
def __init__(self,size):
self.table =[None] * size
self.size = size

hashKey method

def hashKey(self,key) -> int:
"""
ord  -> built-in method that returns the Unicode code of a character
size -> the hash table length
using (hashedString % self.size) -> for not getting an index out of the range of our  hash table length
"""
hashedString = 0
for character in key:
hashedString += ord(character)
return hashedString % self.size

"""
The Logic:
self.table[idx] is None
=> create a linked list and insert into it a node that contains the giving key and the giving value
self.table[idx] is not None:
=> insert into the linked list a node that contains the giving key and the giving value
"""
idx = self.hashKey(key)
if self.table[idx] is None:
else:
self.table[idx].insertAtLast(key, value)

get method

def get(self, key) -> any:
idx = self.hashKey(key)
if self.table[idx] is not None:
return self.table[idx].find(key)

delete method

def delete(self, key):
idx = self.hashKey(key)
if self.table[idx] is not None:
self.table[idx].remove(key)

printAll

def printAll(self):
for i in self.table:
if i is not None:
i.printAll()

All hash table methods

class HashTable:
def __init__(self,size):
self.table =[None] * size
self.size = size

def hashKey(self,key) -> int:
"""
ord  -> built-in method that returns the Unicode code of a character
size -> the hash table length
using (hashedString % self.size) -> for not getting an index out of the range of our  hash table length
"""
hashedString = 0
for character in key:
hashedString += ord(character)
return hashedString % self.size

"""
The Logic:
self.table[idx] is None
=> create a linked list and insert into it a node that contains the giving key and the giving value
self.table[idx] is not None:
=> insert into the linked list a node that contains the giving key and the giving value
"""
idx = self.hashKey(key)
if self.table[idx] is None:
else:
self.table[idx].insertAtLast(key, value)

def get(self, key) -> any:
idx = self.hashKey(key)
if self.table[idx] is not None:
return self.table[idx].find(key)

def delete(self, key):
idx = self.hashKey(key)
if self.table[idx] is not None:
self.table[idx].remove(key)

def printAll(self):
for i in self.table:
if i is not None:
i.printAll()

Final Code

class Node:
def __init__(self,key,value,next = None):
self.key = key
self.value = value
self.next = next

def __init__(self)    :
self.size = 0

def insertAtFirst(self,key,value):
self.size += 1

def insertAtLast(self,key,value):
while current.next:
current = current.next
current.next = Node(key,value)
self.size+=1

def remove(self, key):
previous = None
if current.key == key:
else:
while current.next:
previous = current
current = current.next
if current.key == key:
previous.next = current.next
self.size -= 1

def find(self, key):
while current:
if current.key == key:
return current.value
current = current.next

def printAll(self):
while current:
print(current.key,current.value)
current = current.next

class HashTable:
def __init__(self,size):
self.table =[None] * size
self.size = size

def hashKey(self,key) -> int:
"""
ord  -> built-in method that returns the Unicode code of a character
size -> the hash table length
using (hashedString % self. size) -> for not getting an index out of the range of our  hash table length
"""
hashedString = 0
for character in key:
hashedString += ord(character)
return hashedString % self.size

"""
The Logic:
self.table[idx] is None
=> create a linked list and insert into it a node that contains the giving key and the giving value
self.table[idx] is not None:
=> insert into the linked list a node that contains the giving key and the giving value
"""
idx = self.hashKey(key)
if self.table[idx] is None:
else:
self.table[idx].insertAtLast(key, value)

def get(self, key) -> any:
idx = self.hashKey(key)
if self.table[idx] is not None:
return self.table[idx].find(key)

def delete(self, key):
idx = self.hashKey(key)
if self.table[idx] is not None:
self.table[idx].remove(key)

def printAll(self):
for i in self.table:
if i is not None:
i.printAll()

Exercises

References and useful Resources

Have a great day :)

Discussion (2)

Mayank Pathak

Great explaination @ayabouchiha

Aya Bouchiha

Thank you so much @mayankpathak 🙏🙏
Have a good day 😊