mirror of
https://github.com/trekhleb/javascript-algorithms.git
synced 2026-03-13 08:51:02 +08:00
Add HashTable.
This commit is contained in:
36
src/data-structures/hash-table/HashTable.js
Normal file
36
src/data-structures/hash-table/HashTable.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import LinkedList from '../linked-list/LinkedList';
|
||||
|
||||
const defaultHashTableSize = 32;
|
||||
|
||||
export default class HashTable {
|
||||
constructor(hashTableSize = defaultHashTableSize) {
|
||||
// Create hash table of certain size and fill each bucket with empty linked list.
|
||||
this.buckets = Array(hashTableSize).fill(null).map(() => new LinkedList());
|
||||
}
|
||||
|
||||
// Converts key string to hash number.
|
||||
hash(key) {
|
||||
const hash = Array.from(key).reduce(
|
||||
(hashAccumulator, keySymbol) => (hashAccumulator + keySymbol.charCodeAt(0)),
|
||||
0,
|
||||
);
|
||||
|
||||
// Reduce hash number so it would fit hash table size.
|
||||
return hash % this.buckets.length;
|
||||
}
|
||||
|
||||
insert(key, value) {
|
||||
const bucketLinkedList = this.buckets[this.hash(key)];
|
||||
bucketLinkedList.appendUnique({ key, value });
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const bucketLinkedList = this.buckets[this.hash(key)];
|
||||
return bucketLinkedList.deleteByKey(key);
|
||||
}
|
||||
|
||||
get(key) {
|
||||
const bucketLinkedList = this.buckets[this.hash(key)];
|
||||
return bucketLinkedList.findByKey(key);
|
||||
}
|
||||
}
|
||||
9
src/data-structures/hash-table/README.md
Normal file
9
src/data-structures/hash-table/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Hashed Table
|
||||
|
||||
|Operation |Complexity |
|
||||
|---------------------------|-------------------|
|
||||
|Find |O(1)* |
|
||||
|Insert |O(1)* |
|
||||
|Delete |O(1)* |
|
||||
|
||||
* - assuming that we have "good" hash function and big enough hash table size so that collisions are rare.
|
||||
49
src/data-structures/hash-table/__test__/HashTable.test.js
Normal file
49
src/data-structures/hash-table/__test__/HashTable.test.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import HashTable from '../HashTable';
|
||||
|
||||
describe('HashTable', () => {
|
||||
it('should create hash table of certain size', () => {
|
||||
const defaultHashTable = new HashTable();
|
||||
expect(defaultHashTable.buckets.length).toBe(32);
|
||||
|
||||
const biggerHashTable = new HashTable(64);
|
||||
expect(biggerHashTable.buckets.length).toBe(64);
|
||||
});
|
||||
|
||||
it('should generate proper hash for specified keys', () => {
|
||||
const hashTable = new HashTable();
|
||||
|
||||
expect(hashTable.hash('a')).toBe(1);
|
||||
expect(hashTable.hash('b')).toBe(2);
|
||||
expect(hashTable.hash('abc')).toBe(6);
|
||||
});
|
||||
|
||||
it('should insert, read and delete data with collisions', () => {
|
||||
const hashTable = new HashTable(3);
|
||||
|
||||
expect(hashTable.hash('a')).toBe(1);
|
||||
expect(hashTable.hash('b')).toBe(2);
|
||||
expect(hashTable.hash('c')).toBe(0);
|
||||
expect(hashTable.hash('d')).toBe(1);
|
||||
|
||||
hashTable.insert('a', 'sky-old');
|
||||
hashTable.insert('a', 'sky');
|
||||
hashTable.insert('b', 'sea');
|
||||
hashTable.insert('c', 'earth');
|
||||
hashTable.insert('d', 'ocean');
|
||||
|
||||
expect(hashTable.buckets[0].toString()).toBe('c:earth');
|
||||
expect(hashTable.buckets[1].toString()).toBe('a:sky,d:ocean');
|
||||
expect(hashTable.buckets[2].toString()).toBe('b:sea');
|
||||
|
||||
expect(hashTable.get('a').value).toBe('sky');
|
||||
expect(hashTable.get('d').value).toBe('ocean');
|
||||
|
||||
hashTable.delete('a');
|
||||
|
||||
expect(hashTable.get('a')).toBeNull();
|
||||
expect(hashTable.get('d').value).toBe('ocean');
|
||||
|
||||
hashTable.insert('d', 'ocean-new');
|
||||
expect(hashTable.get('d').value).toBe('ocean-new');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user