Implementing a Hash Table in JavaScript
Hash tables are fundamental data structures used for efficient key-value storage and retrieval. This challenge asks you to implement a basic hash table in JavaScript, focusing on core functionalities like insertion, retrieval, deletion, and handling collisions. Building a hash table will solidify your understanding of data structures and algorithms, and is a crucial skill for many programming tasks.
Problem Description
You are tasked with creating a HashTable class in JavaScript. This class should provide the following functionalities:
constructor(): Initializes an empty hash table. It should include atableproperty (an array) and asizeproperty (initially 0).hash(key): A function that takes a key as input and returns a numerical hash code. For simplicity, you can use a basic hashing function like summing the character codes of the key string. Ensure the hash code is within the bounds of thetablearray.set(key, value): Inserts a key-value pair into the hash table. If the key already exists, update its value. Handle collisions using separate chaining (each index in thetablearray will hold a linked list of key-value pairs).get(key): Retrieves the value associated with a given key. Returnundefinedif the key is not found.delete(key): Removes the key-value pair associated with a given key.size(): Returns the number of key-value pairs currently stored in the hash table.
Key Requirements:
- Implement separate chaining for collision resolution. You can use JavaScript arrays to represent the linked lists at each index.
- The
hashfunction should distribute keys reasonably well to minimize collisions. - The
set,get, anddeletemethods should have an average time complexity of O(1). - Handle edge cases such as empty keys and values.
Expected Behavior:
The hash table should behave as expected for insertion, retrieval, and deletion of key-value pairs. Collisions should be handled gracefully, and the size property should accurately reflect the number of elements in the table.
Examples
Example 1:
Input:
const hashTable = new HashTable();
hashTable.set('name', 'Alice');
hashTable.set('age', 30);
hashTable.set('city', 'New York');
Output:
hashTable.get('name'); // 'Alice'
hashTable.get('age'); // 30
hashTable.get('city'); // 'New York'
hashTable.get('country'); // undefined
Explanation: The hash table successfully stores and retrieves the key-value pairs. Retrieving a non-existent key returns undefined.
Example 2:
Input:
const hashTable = new HashTable();
hashTable.set('a', 1);
hashTable.set('b', 2);
hashTable.set('c', 3);
hashTable.set('a', 4); // Update existing key
Output:
hashTable.get('a'); // 4
hashTable.get('b'); // 2
hashTable.get('c'); // 3
hashTable.size(); // 3
Explanation: Updating an existing key correctly overwrites the previous value. The size remains unchanged as we only updated a value, not added a new key.
Example 3: (Collision Scenario)
Input:
const hashTable = new HashTable();
hashTable.set('key1', 'value1');
hashTable.set('key2', 'value2'); // Assume 'key1' and 'key2' hash to the same index
hashTable.get('key1'); // 'value1'
hashTable.get('key2'); // 'value2'
hashTable.delete('key1');
hashTable.get('key1'); // undefined
hashTable.get('key2'); // 'value2'
Explanation: Demonstrates collision handling. Both keys hash to the same index, but retrieval and deletion work correctly due to separate chaining.
Constraints
- Keys can be strings.
- Values can be any JavaScript data type.
- The maximum number of key-value pairs the hash table can store is 1000. (This is to prevent excessive memory usage during testing).
- The
hashfunction should produce a non-negative integer. - The average time complexity for
set,get, anddeleteoperations should be O(1). Worst-case complexity (due to collisions) can be O(n), where n is the number of elements in a chain.
Notes
- Consider the trade-offs between different hashing functions. A good hashing function minimizes collisions.
- Think about how to handle resizing the hash table if it becomes too full. (This is not required for this challenge, but it's a good consideration for a production-ready hash table).
- Focus on the core functionalities of a hash table. Error handling and edge cases are important, but prioritize implementing the basic operations correctly.
- Remember that separate chaining involves using linked lists (represented by JavaScript arrays in this case) to store multiple key-value pairs that hash to the same index.