Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Hash Table Data Structure in Javascript
Hash Table is a data structure which stores data in an associative manner. In a hash table, data is stored in an array format, where each data value has its own unique index value. Access to data becomes very fast if we know the index of the desired data.
Thus, it becomes a data structure in which insertion and search operations are very fast irrespective of the size of the data. Hash Table uses an array as a storage medium and uses the hash technique to generate an index where an element is to be inserted or is to be located from.
Hashing
Hashing is a technique to convert a range of key values into a range of indexes of an array. We're going to use modulo operator to get a range of key values. Consider an example of a hash table of size 20, and the following items are to be stored. Item is in the (key, value) format.
Here we have a hash function that takes in keys and generates indices for a table. These indices let us know where the value is stored. Now whenever we want to search for a value associated with a key, we just need to run the hash function on the key again and get the value in nearly constant time.
Hash functions are pretty hard to design though. Let's take an example:
Let's say we have the following hash function:
Hash Function Example
function modBy11(key) {
return key % 11;
}
// Testing the hash function
console.log("Hash of 15:", modBy11(15)); // 4
console.log("Hash of 25:", modBy11(25)); // 3
console.log("Hash of 8:", modBy11(8)); // 8
console.log("Hash of 26:", modBy11(26)); // 4 (collision!)
Hash of 15: 4 Hash of 25: 3 Hash of 8: 8 Hash of 26: 4
And we start running this on key-value pairs we want to store, for example:
- (15, 20) - Hash code: 4
- (25, 39) - Hash code: 3
- (8, 55) - Hash code: 8
- (26, 84) - Hash code: 4
Here we see that we have a collision, ie, if we were to store 15 first and then encounter the key 26 with this hash function, it'll try to fix this entry in the same hole. This is called a collision. And to handle such situations, we need to define a collision handling mechanism. There are some well defined simple collision resolution algorithms. For example:
Collision Resolution Techniques
- Linear Probing: In this algorithm, we can search the next empty location in the array by looking into the next cell until we find an empty cell. In our example, since hole at 4 is taken, we can fill it in 5.
- Separate Chaining: In this implementation, we associate each location in the hash table with a list. Whenever we get a collision, we append the key-value pair at the end of this list. This can lead to much longer search times if chains keep getting longer.
Now that we understand how a hash table works and how we can use collision resolution, let's implement the HashTable class.
HashTable Implementation
class HashTable {
constructor(size = 10) {
this.size = size;
this.table = new Array(size);
}
// Hash function using modulo
hash(key) {
return key % this.size;
}
// Add key-value pair
put(key, value) {
const index = this.hash(key);
if (!this.table[index]) {
this.table[index] = [];
}
// Check if key already exists
const existing = this.table[index].find(item => item.key === key);
if (existing) {
existing.value = value;
} else {
this.table[index].push({ key, value });
}
}
// Get value by key
get(key) {
const index = this.hash(key);
const bucket = this.table[index];
if (bucket) {
const found = bucket.find(item => item.key === key);
return found ? found.value : undefined;
}
return undefined;
}
// Remove key-value pair
remove(key) {
const index = this.hash(key);
const bucket = this.table[index];
if (bucket) {
const itemIndex = bucket.findIndex(item => item.key === key);
if (itemIndex > -1) {
bucket.splice(itemIndex, 1);
return true;
}
}
return false;
}
// Display all key-value pairs
display() {
for (let i = 0; i < this.size; i++) {
if (this.table[i]) {
console.log(`Index ${i}:`, this.table[i]);
}
}
}
}
// Example usage
const hashTable = new HashTable(7);
hashTable.put(15, "fifteen");
hashTable.put(25, "twenty-five");
hashTable.put(8, "eight");
hashTable.put(26, "twenty-six");
console.log("Getting value for key 15:", hashTable.get(15));
console.log("Getting value for key 26:", hashTable.get(26));
hashTable.display();
Getting value for key 15: fifteen
Getting value for key 26: twenty-six
Index 1: [ { key: 15, value: 'fifteen' }, { key: 26, value: 'twenty-six' } ]
Index 4: [ { key: 25, value: 'twenty-five' } ]
Index 5: [ { key: 8, value: 'eight' } ]
Key Methods Implemented
We've implemented these essential methods in our HashTable implementation:
- put(key, value): Adds a new key-value pair to the hash table
- get(key): Gets the value associated with a key
- remove(key): Removes the key-value pair from the table
- display(): Shows all stored key-value pairs
- hash(key): Internal hash function to compute index
Time Complexity
| Operation | Average Case | Worst Case |
|---|---|---|
| Insert | O(1) | O(n) |
| Search | O(1) | O(n) |
| Delete | O(1) | O(n) |
Conclusion
Hash tables provide efficient data storage and retrieval with average O(1) time complexity. The key to good performance is choosing an appropriate hash function and collision resolution strategy to minimize collisions.
