Skip to main content

Collision Handling in Hashing

Overview​

In hashing, collision handling refers to the methods used to resolve the issue when two keys hash to the same index in a hash table. Collisions are inevitable in hash tables due to the limited number of available slots compared to the potentially infinite number of input keys.

Methods of Collision Handling​

1. Chaining (Open Hashing)​

  • Chaining stores multiple elements in the same bucket using a data structure like a linked list.
  • When a collision occurs, the new key-value pair is added to the end of the linked list at that index.
  • Advantages: Simple to implement, no need to resize the hash table.
  • Disadvantages: Requires extra memory for pointers, performance degrades if many elements collide at the same index.

2. Open Addressing (Closed Hashing)​

  • In open addressing, all elements are stored within the hash table itself, and when a collision occurs, alternative slots are probed to find an empty one.
  • Common probing techniques include:
    • Linear Probing: Increment the index sequentially until an empty slot is found.
    • Quadratic Probing: Probe at quadratic intervals (i.e., 1, 4, 9, ...).
    • Double Hashing: Use a second hash function to determine the probe step.
  • Advantages: No need for extra memory for pointers, can be efficient for smaller tables.
  • Disadvantages: Can lead to clustering (for linear probing), needs good probing strategies to avoid performance degradation.

Example: Chaining in Python​

class HashTable:
def __init__(self):
self.table = [[] for _ in range(10)] # Hash table with 10 slots

def insert(self, key, value):
index = hash(key) % len(self.table)
for pair in self.table[index]:
if pair[0] == key:
pair[1] = value # Update if key exists
return
self.table[index].append([key, value]) # Add new key-value pair

def search(self, key):
index = hash(key) % len(self.table)
for pair in self.table[index]:
if pair[0] == key:
return pair[1]
return None

def delete(self, key):
index = hash(key) % len(self.table)
for i, pair in enumerate(self.table[index]):
if pair[0] == key:
del self.table[index][i]
return



# Example usage
hash_table = HashTable()
hash_table.insert('apple', 1)
hash_table.insert('banana', 2)
hash_table.insert('orange', 3)
print(hash_table.search('banana')) # Output: 2
hash_table.delete('banana')
print(hash_table.search('banana')) # Output: None

Example: Chaining in JavaScript​

class HashTable {
constructor() {
this.table = Array.from({ length: 10 }, () => []); // Hash table with 10 slots
}

hash(key) {
let hash = 0;
for (let char of key.toString()) {
hash += char.charCodeAt(0);
}
return hash % this.table.length; // Simple hash function
}

insert(key, value) {
const index = this.hash(key);
for (let pair of this.table[index]) {
if (pair[0] === key) {
pair[1] = value; // Update if key exists
return;
}
}
this.table[index].push([key, value]); // Add new key-value pair
}

search(key) {
const index = this.hash(key);
for (let pair of this.table[index]) {
if (pair[0] === key) {
return pair[1]; // Return the value if key is found
}
}
return null; // Key not found
}

delete(key) {
const index = this.hash(key);
this.table[index] = this.table[index].filter(pair => pair[0] !== key); // Remove the key-value pair
}
}

// Example usage
const hashTable = new HashTable();
hashTable.insert('apple', 1);
hashTable.insert('banana', 2);
hashTable.insert('orange', 3);
console.log(hashTable.search('banana')); // Output: 2
hashTable.delete('banana');
console.log(hashTable.search('banana')); // Output: null