diff --git a/skeletons/data-structures/hash-table/HashTable.js b/skeletons/data-structures/hash-table/HashTable.js
index 8c9ce7f..a2fbd37 100644
--- a/skeletons/data-structures/hash-table/HashTable.js
+++ b/skeletons/data-structures/hash-table/HashTable.js
@@ -1,51 +1,42 @@
-import LinkedList from '../linked-list/LinkedList';
+import LinkedList from '../../../src/data-structures/linked-list/LinkedList';
-// Hash table size directly affects on the number of collisions.
-// The bigger the hash table size the less collisions you'll get.
-// For demonstrating purposes hash table size is small to show how collisions
-// are being handled.
-const defaultHashTableSize = 32;
+const DEFAULT_SIZE = 32;
export default class HashTable {
/**
* @param {number} hashTableSize
*/
- constructor(hashTableSize = defaultHashTableSize) {}
+ constructor(size = DEFAULT_SIZE) {}
/**
* Converts key string to hash number.
- *asadsd
+ *
* @param {string} key
* @return {number}
*/
hash(key) {}
- /**
- * @param {string} key
- * @param {*} value
- */
- set(key, value) {}
-
/**
* @param {string} key
* @return {*}
*/
- delete(key) {}
+ get(key) {}
/**
* @param {string} key
- * @return {*}
+ * @return {boolean}
*/
- get(key) {}
+ has(key) {}
/**
* @param {string} key
- * @return {boolean}
+ * @param {*} value
*/
- has(key) {}
+ set(key, value) {}
/**
- * @return {string[]}
+ * @param {string} key
+ * @return {*}
*/
- getKeys() {}
+ delete(key) {}
}
diff --git a/skeletons/data-structures/hash-table/README.md b/skeletons/data-structures/hash-table/README.md
index 59b5194..2ca408d 100644
--- a/skeletons/data-structures/hash-table/README.md
+++ b/skeletons/data-structures/hash-table/README.md
@@ -1,26 +1,111 @@
# Hash Table
-In computing, a hash table (hash map) is a data
-structure which implements an associative array
-abstract data type, a structure that can map keys
-to values. A hash table uses a hash function to
-compute an index into an array of buckets or slots,
-from which the desired value can be found
+## Description
-Ideally, the hash function will assign each key to a
-unique bucket, but most hash table designs employ an
-imperfect hash function, which might cause hash
-collisions where the hash function generates the same
-index for more than one key. Such collisions must be
-accommodated in some way.
+Watch both videos about hash tables:
-
+
+[Data Structures: Hash Tables](https://www.youtube.com/watch?v=0M_kIqhwbFo) (6 Minutes)
-Hash collision resolved by separate chaining.
+
+[Hash Tables and Hash Functions by Kevin Drumm](https://www.youtube.com/watch?v=KyUTuwz_b7Q) (14 Minutes)
-
+The first video provides a great introduction to the what a hash table is, and what it's used for. The second video provides the explanation of the actual implementation (and the speaker has an awesome British accent).
-## References
+## Implementation
-- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)
-- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- `constructor(size)`
+ - Write a function that instantiates the buckets.
+- `hash(key)`
+ - Write a function that generates the hash of the key.
+- `get(key)`
+ - Write a function that retrieves an item from the hash table.
+- `has(key)`
+ - Write a function that returns whether or not the item exists in the hash.
+- `set(key, value)`
+ - Write a function that sets an item in the hash table.
+- `delete(key)`
+ - Write a function that deletes an item in the hash table.
+
+## Walkthrough
+
+### `constructor()`
+
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ ```
+- Create an array with the size specified.
+- Each index in the array is usually called a bucket.
+- Fill each bucket in the array with a linked list.
+
+### `hash(key)`
+
+- Generate the index of the bucket.
+- Usage:
+ ```
+ const hash = this.hash('a') // hash => 1
+ ```
+- There are numerous ways to generate a hash, and for this exercise, we will simply map `a` to `1`, `b` to `2`, `c` to `3` and on.
+ - Examples:
+ ```
+ hash('a') // 1
+ hash('b') // 2
+ hash('ab') // 3 = 1 + 2
+ hash('abc') // 6 = 1 + 2 + 3
+ ```
+- Once the hash value is generated, `mod` it by the length of the buckets to map it to the buckets.
+
+### `get(key)`
+
+- Retrieves the value for the stored key.
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ hashTable.set('a', 1);
+ hashTable.get('a'); // 1
+ ```
+- Utilize the `this.hash(key)` funtion in order to access the find the linked list.
+- Utilize the found linked list's `find` function to locate the linked list node with the value.
+ - The find function also takes a custom callback.
+ - Use the callback function to find the node with the correct key
+
+### `has(key)`
+
+- Returns whether the key exists in the hash table.
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ hashTable.has('a'); // false
+ ```
+- Utilize the `get()` function written previously to return whether the hash table contains the key.
+
+### `set(key, value)`
+
+- Stores the key/value pair into the hash table.
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ hashTable.set('a', 1);
+ hashTable.get('a'); // 1
+ hashTable.set('a', 2);
+ hashTable.get('a'); // 2
+ ```
+- Locate the correct bucket by utilizing the `hash()` function.
+- Check if the linked list in the bucket contains an entry with the key.
+- If the key exists, delete the key.
+ - When you call `set('a', 1)` then `set('a', 2)`, the expected value is `2`.
+- Add a new entry for the key/value pair to the linked list.
+
+### `delete(key)`
+
+- Delete the key/value pair from the hash table.
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ hashTable.set('a', 1);
+ hashTable.delete('a');
+ hashTable.has('a'); // false
+ ```
diff --git a/skeletons/data-structures/hash-table/__test__/HashTable.test.js b/skeletons/data-structures/hash-table/__test__/HashTable.test.js
index cc32215..6e7a1fb 100644
--- a/skeletons/data-structures/hash-table/__test__/HashTable.test.js
+++ b/skeletons/data-structures/hash-table/__test__/HashTable.test.js
@@ -17,6 +17,20 @@ describe('HashTable', () => {
expect(hashTable.hash('abc')).toBe(6);
});
+ it('should be possible to add objects to hash table', () => {
+ const hashTable = new HashTable();
+
+ hashTable.set('objectKey', {
+ prop1: 'a',
+ prop2: 'b'
+ });
+
+ const object = hashTable.get('objectKey');
+ expect(object).toBeDefined();
+ expect(object.prop1).toBe('a');
+ expect(object.prop2).toBe('b');
+ });
+
it('should set, read and delete data with collisions', () => {
const hashTable = new HashTable(3);
@@ -43,47 +57,16 @@ describe('HashTable', () => {
expect(hashTable.get('a')).toBe('sky');
expect(hashTable.get('d')).toBe('ocean');
- expect(hashTable.get('x')).not.toBeDefined();
+ expect(hashTable.get('x')).toBeNull();
hashTable.delete('a');
expect(hashTable.delete('not-existing')).toBeNull();
- expect(hashTable.get('a')).not.toBeDefined();
+ expect(hashTable.get('a')).toBeNull();
expect(hashTable.get('d')).toBe('ocean');
hashTable.set('d', 'ocean-new');
expect(hashTable.get('d')).toBe('ocean-new');
});
-
- it('should be possible to add objects to hash table', () => {
- const hashTable = new HashTable();
-
- hashTable.set('objectKey', { prop1: 'a', prop2: 'b' });
-
- const object = hashTable.get('objectKey');
- expect(object).toBeDefined();
- expect(object.prop1).toBe('a');
- expect(object.prop2).toBe('b');
- });
-
- it('should track actual keys', () => {
- const hashTable = new HashTable(3);
-
- hashTable.set('a', 'sky-old');
- hashTable.set('a', 'sky');
- hashTable.set('b', 'sea');
- hashTable.set('c', 'earth');
- hashTable.set('d', 'ocean');
-
- expect(hashTable.getKeys()).toEqual(['a', 'b', 'c', 'd']);
- expect(hashTable.has('a')).toBeTruthy();
- expect(hashTable.has('x')).toBeFalsy();
-
- hashTable.delete('a');
-
- expect(hashTable.has('a')).toBeFalsy();
- expect(hashTable.has('b')).toBeTruthy();
- expect(hashTable.has('x')).toBeFalsy();
- });
});
diff --git a/solutions/data-structures/hash-table/HashTable.js b/solutions/data-structures/hash-table/HashTable.js
index 51575f9..e3aa96f 100644
--- a/solutions/data-structures/hash-table/HashTable.js
+++ b/solutions/data-structures/hash-table/HashTable.js
@@ -1,21 +1,13 @@
-import LinkedList from '../linked-list/LinkedList';
+import LinkedList from '../../../solutions/data-structures/linked-list/LinkedList';
-// Hash table size directly affects on the number of collisions.
-// The bigger the hash table size the less collisions you'll get.
-// For demonstrating purposes hash table size is small to show how collisions
-// are being handled.
-const defaultHashTableSize = 32;
+const DEFAULT_SIZE = 32;
export default class HashTable {
/**
* @param {number} hashTableSize
*/
- 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());
-
- // Just to keep track of all actual keys in a fast way.
- this.keys = {};
+ constructor(size = DEFAULT_SIZE) {
+ this.buckets = Array(size).fill().map(() => new LinkedList());
}
/**
@@ -25,74 +17,72 @@ export default class HashTable {
* @return {number}
*/
hash(key) {
- const hash = Array.from(key).reduce(
- (hashAccumulator, keySymbol) => (hashAccumulator + keySymbol.charCodeAt(0)),
- 0,
- );
+ const hashNum = Array.from(key).reduce((hash, char) => hash += char.charCodeAt(0), 0);
+ return hashNum % this.buckets.length;
+ }
+
+ /**
+ * @param {string} key
+ * @return {*}
+ */
+ get(key) {
+ const hash = this.hash(key);
+
+ const foundItem = this.buckets[hash].find({
+ callback: nodeValue => nodeValue.key === key,
+ });
- // Reduce hash number so it would fit hash table size.
- return hash % this.buckets.length;
+ return foundItem && foundItem.value.value;
}
/**
* @param {string} key
- * @param {*} value
+ * @return {boolean}
*/
- set(key, value) {
- const keyHash = this.hash(key);
- this.keys[key] = keyHash;
- const bucketLinkedList = this.buckets[keyHash];
- const node = bucketLinkedList.find({ callback: nodeValue => nodeValue.key === key });
-
- if (!node) {
- // Insert new node.
- bucketLinkedList.append({ key, value });
- } else {
- // Update value of existing node.
- node.value.value = value;
- }
+ has(key) {
+ return !!this.get(key);
}
/**
* @param {string} key
- * @return {*}
+ * @param {*} value
*/
- delete(key) {
- const keyHash = this.hash(key);
- delete this.keys[key];
- const bucketLinkedList = this.buckets[keyHash];
- const node = bucketLinkedList.find({ callback: nodeValue => nodeValue.key === key });
+ set(key, value) {
+ const hash = this.hash(key);
+ const bucket = this.buckets[hash];
+
+ const node = this.buckets[hash].find({
+ callback: nodeValue => nodeValue.key === key,
+ })
if (node) {
- return bucketLinkedList.delete(node.value);
+ bucket.delete(node.value);
}
- return null;
+ bucket.append({
+ key,
+ value
+ });
}
/**
* @param {string} key
* @return {*}
*/
- get(key) {
- const bucketLinkedList = this.buckets[this.hash(key)];
- const node = bucketLinkedList.find({ callback: nodeValue => nodeValue.key === key });
+ delete(key) {
+ if (this.has(key)) {
+ const hash = this.hash(key);
+ const bucket = this.buckets[hash];
- return node ? node.value.value : undefined;
- }
+ const node = bucket.find({
+ callback: value => value.key === key,
+ })
- /**
- * @param {string} key
- * @return {boolean}
- */
- has(key) {
- return Object.hasOwnProperty.call(this.keys, key);
- }
+ bucket.delete(node.value);
- /**
- * @return {string[]}
- */
- getKeys() {
- return Object.keys(this.keys);
+ return node;
+ }
+
+ return null;
}
}
diff --git a/solutions/data-structures/hash-table/README.md b/solutions/data-structures/hash-table/README.md
index 59b5194..2ca408d 100644
--- a/solutions/data-structures/hash-table/README.md
+++ b/solutions/data-structures/hash-table/README.md
@@ -1,26 +1,111 @@
# Hash Table
-In computing, a hash table (hash map) is a data
-structure which implements an associative array
-abstract data type, a structure that can map keys
-to values. A hash table uses a hash function to
-compute an index into an array of buckets or slots,
-from which the desired value can be found
+## Description
-Ideally, the hash function will assign each key to a
-unique bucket, but most hash table designs employ an
-imperfect hash function, which might cause hash
-collisions where the hash function generates the same
-index for more than one key. Such collisions must be
-accommodated in some way.
+Watch both videos about hash tables:
-
+
+[Data Structures: Hash Tables](https://www.youtube.com/watch?v=0M_kIqhwbFo) (6 Minutes)
-Hash collision resolved by separate chaining.
+
+[Hash Tables and Hash Functions by Kevin Drumm](https://www.youtube.com/watch?v=KyUTuwz_b7Q) (14 Minutes)
-
+The first video provides a great introduction to the what a hash table is, and what it's used for. The second video provides the explanation of the actual implementation (and the speaker has an awesome British accent).
-## References
+## Implementation
-- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)
-- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- `constructor(size)`
+ - Write a function that instantiates the buckets.
+- `hash(key)`
+ - Write a function that generates the hash of the key.
+- `get(key)`
+ - Write a function that retrieves an item from the hash table.
+- `has(key)`
+ - Write a function that returns whether or not the item exists in the hash.
+- `set(key, value)`
+ - Write a function that sets an item in the hash table.
+- `delete(key)`
+ - Write a function that deletes an item in the hash table.
+
+## Walkthrough
+
+### `constructor()`
+
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ ```
+- Create an array with the size specified.
+- Each index in the array is usually called a bucket.
+- Fill each bucket in the array with a linked list.
+
+### `hash(key)`
+
+- Generate the index of the bucket.
+- Usage:
+ ```
+ const hash = this.hash('a') // hash => 1
+ ```
+- There are numerous ways to generate a hash, and for this exercise, we will simply map `a` to `1`, `b` to `2`, `c` to `3` and on.
+ - Examples:
+ ```
+ hash('a') // 1
+ hash('b') // 2
+ hash('ab') // 3 = 1 + 2
+ hash('abc') // 6 = 1 + 2 + 3
+ ```
+- Once the hash value is generated, `mod` it by the length of the buckets to map it to the buckets.
+
+### `get(key)`
+
+- Retrieves the value for the stored key.
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ hashTable.set('a', 1);
+ hashTable.get('a'); // 1
+ ```
+- Utilize the `this.hash(key)` funtion in order to access the find the linked list.
+- Utilize the found linked list's `find` function to locate the linked list node with the value.
+ - The find function also takes a custom callback.
+ - Use the callback function to find the node with the correct key
+
+### `has(key)`
+
+- Returns whether the key exists in the hash table.
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ hashTable.has('a'); // false
+ ```
+- Utilize the `get()` function written previously to return whether the hash table contains the key.
+
+### `set(key, value)`
+
+- Stores the key/value pair into the hash table.
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ hashTable.set('a', 1);
+ hashTable.get('a'); // 1
+ hashTable.set('a', 2);
+ hashTable.get('a'); // 2
+ ```
+- Locate the correct bucket by utilizing the `hash()` function.
+- Check if the linked list in the bucket contains an entry with the key.
+- If the key exists, delete the key.
+ - When you call `set('a', 1)` then `set('a', 2)`, the expected value is `2`.
+- Add a new entry for the key/value pair to the linked list.
+
+### `delete(key)`
+
+- Delete the key/value pair from the hash table.
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ hashTable.set('a', 1);
+ hashTable.delete('a');
+ hashTable.has('a'); // false
+ ```
diff --git a/solutions/data-structures/hash-table/__test__/HashTable.test.js b/solutions/data-structures/hash-table/__test__/HashTable.test.js
index cc32215..6e7a1fb 100644
--- a/solutions/data-structures/hash-table/__test__/HashTable.test.js
+++ b/solutions/data-structures/hash-table/__test__/HashTable.test.js
@@ -17,6 +17,20 @@ describe('HashTable', () => {
expect(hashTable.hash('abc')).toBe(6);
});
+ it('should be possible to add objects to hash table', () => {
+ const hashTable = new HashTable();
+
+ hashTable.set('objectKey', {
+ prop1: 'a',
+ prop2: 'b'
+ });
+
+ const object = hashTable.get('objectKey');
+ expect(object).toBeDefined();
+ expect(object.prop1).toBe('a');
+ expect(object.prop2).toBe('b');
+ });
+
it('should set, read and delete data with collisions', () => {
const hashTable = new HashTable(3);
@@ -43,47 +57,16 @@ describe('HashTable', () => {
expect(hashTable.get('a')).toBe('sky');
expect(hashTable.get('d')).toBe('ocean');
- expect(hashTable.get('x')).not.toBeDefined();
+ expect(hashTable.get('x')).toBeNull();
hashTable.delete('a');
expect(hashTable.delete('not-existing')).toBeNull();
- expect(hashTable.get('a')).not.toBeDefined();
+ expect(hashTable.get('a')).toBeNull();
expect(hashTable.get('d')).toBe('ocean');
hashTable.set('d', 'ocean-new');
expect(hashTable.get('d')).toBe('ocean-new');
});
-
- it('should be possible to add objects to hash table', () => {
- const hashTable = new HashTable();
-
- hashTable.set('objectKey', { prop1: 'a', prop2: 'b' });
-
- const object = hashTable.get('objectKey');
- expect(object).toBeDefined();
- expect(object.prop1).toBe('a');
- expect(object.prop2).toBe('b');
- });
-
- it('should track actual keys', () => {
- const hashTable = new HashTable(3);
-
- hashTable.set('a', 'sky-old');
- hashTable.set('a', 'sky');
- hashTable.set('b', 'sea');
- hashTable.set('c', 'earth');
- hashTable.set('d', 'ocean');
-
- expect(hashTable.getKeys()).toEqual(['a', 'b', 'c', 'd']);
- expect(hashTable.has('a')).toBeTruthy();
- expect(hashTable.has('x')).toBeFalsy();
-
- hashTable.delete('a');
-
- expect(hashTable.has('a')).toBeFalsy();
- expect(hashTable.has('b')).toBeTruthy();
- expect(hashTable.has('x')).toBeFalsy();
- });
});
diff --git a/solutions/data-structures/linked-list/LinkedList.js b/solutions/data-structures/linked-list/LinkedList.js
index 855feee..47a1109 100644
--- a/solutions/data-structures/linked-list/LinkedList.js
+++ b/solutions/data-structures/linked-list/LinkedList.js
@@ -66,7 +66,7 @@ export default class LinkedList {
if (currentNode !== null) {
// If next node must be deleted then make next node to be a next next one.
- while (currentNode.next) {
+ while (currentNode && currentNode.next) {
if (currentNode.next.value === value) {
deletedNode = currentNode.next;
currentNode.next = currentNode.next.next;
diff --git a/src/data-structures/hash-table/HashTable.js b/src/data-structures/hash-table/HashTable.js
new file mode 100644
index 0000000..a2fbd37
--- /dev/null
+++ b/src/data-structures/hash-table/HashTable.js
@@ -0,0 +1,42 @@
+import LinkedList from '../../../src/data-structures/linked-list/LinkedList';
+
+const DEFAULT_SIZE = 32;
+
+export default class HashTable {
+ /**
+ * @param {number} hashTableSize
+ */
+ constructor(size = DEFAULT_SIZE) {}
+
+ /**
+ * Converts key string to hash number.
+ *
+ * @param {string} key
+ * @return {number}
+ */
+ hash(key) {}
+
+ /**
+ * @param {string} key
+ * @return {*}
+ */
+ get(key) {}
+
+ /**
+ * @param {string} key
+ * @return {boolean}
+ */
+ has(key) {}
+
+ /**
+ * @param {string} key
+ * @param {*} value
+ */
+ set(key, value) {}
+
+ /**
+ * @param {string} key
+ * @return {*}
+ */
+ delete(key) {}
+}
diff --git a/src/data-structures/hash-table/README.md b/src/data-structures/hash-table/README.md
new file mode 100644
index 0000000..2ca408d
--- /dev/null
+++ b/src/data-structures/hash-table/README.md
@@ -0,0 +1,111 @@
+# Hash Table
+
+## Description
+
+Watch both videos about hash tables:
+
+
+[Data Structures: Hash Tables](https://www.youtube.com/watch?v=0M_kIqhwbFo) (6 Minutes)
+
+
+[Hash Tables and Hash Functions by Kevin Drumm](https://www.youtube.com/watch?v=KyUTuwz_b7Q) (14 Minutes)
+
+The first video provides a great introduction to the what a hash table is, and what it's used for. The second video provides the explanation of the actual implementation (and the speaker has an awesome British accent).
+
+## Implementation
+
+- `constructor(size)`
+ - Write a function that instantiates the buckets.
+- `hash(key)`
+ - Write a function that generates the hash of the key.
+- `get(key)`
+ - Write a function that retrieves an item from the hash table.
+- `has(key)`
+ - Write a function that returns whether or not the item exists in the hash.
+- `set(key, value)`
+ - Write a function that sets an item in the hash table.
+- `delete(key)`
+ - Write a function that deletes an item in the hash table.
+
+## Walkthrough
+
+### `constructor()`
+
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ ```
+- Create an array with the size specified.
+- Each index in the array is usually called a bucket.
+- Fill each bucket in the array with a linked list.
+
+### `hash(key)`
+
+- Generate the index of the bucket.
+- Usage:
+ ```
+ const hash = this.hash('a') // hash => 1
+ ```
+- There are numerous ways to generate a hash, and for this exercise, we will simply map `a` to `1`, `b` to `2`, `c` to `3` and on.
+ - Examples:
+ ```
+ hash('a') // 1
+ hash('b') // 2
+ hash('ab') // 3 = 1 + 2
+ hash('abc') // 6 = 1 + 2 + 3
+ ```
+- Once the hash value is generated, `mod` it by the length of the buckets to map it to the buckets.
+
+### `get(key)`
+
+- Retrieves the value for the stored key.
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ hashTable.set('a', 1);
+ hashTable.get('a'); // 1
+ ```
+- Utilize the `this.hash(key)` funtion in order to access the find the linked list.
+- Utilize the found linked list's `find` function to locate the linked list node with the value.
+ - The find function also takes a custom callback.
+ - Use the callback function to find the node with the correct key
+
+### `has(key)`
+
+- Returns whether the key exists in the hash table.
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ hashTable.has('a'); // false
+ ```
+- Utilize the `get()` function written previously to return whether the hash table contains the key.
+
+### `set(key, value)`
+
+- Stores the key/value pair into the hash table.
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ hashTable.set('a', 1);
+ hashTable.get('a'); // 1
+ hashTable.set('a', 2);
+ hashTable.get('a'); // 2
+ ```
+- Locate the correct bucket by utilizing the `hash()` function.
+- Check if the linked list in the bucket contains an entry with the key.
+- If the key exists, delete the key.
+ - When you call `set('a', 1)` then `set('a', 2)`, the expected value is `2`.
+- Add a new entry for the key/value pair to the linked list.
+
+### `delete(key)`
+
+- Delete the key/value pair from the hash table.
+- Usage:
+ ```
+ const hashTable = new HashTable();
+ hashTable.set('a', 1);
+ hashTable.delete('a');
+ hashTable.has('a'); // false
+ ```
diff --git a/src/data-structures/hash-table/__test__/HashTable.test.js b/src/data-structures/hash-table/__test__/HashTable.test.js
new file mode 100644
index 0000000..6e7a1fb
--- /dev/null
+++ b/src/data-structures/hash-table/__test__/HashTable.test.js
@@ -0,0 +1,72 @@
+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 be possible to add objects to hash table', () => {
+ const hashTable = new HashTable();
+
+ hashTable.set('objectKey', {
+ prop1: 'a',
+ prop2: 'b'
+ });
+
+ const object = hashTable.get('objectKey');
+ expect(object).toBeDefined();
+ expect(object.prop1).toBe('a');
+ expect(object.prop2).toBe('b');
+ });
+
+ it('should set, 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.set('a', 'sky-old');
+ hashTable.set('a', 'sky');
+ hashTable.set('b', 'sea');
+ hashTable.set('c', 'earth');
+ hashTable.set('d', 'ocean');
+
+ expect(hashTable.has('x')).toBeFalsy();
+ expect(hashTable.has('b')).toBeTruthy();
+ expect(hashTable.has('c')).toBeTruthy();
+
+ const stringifier = value => `${value.key}:${value.value}`;
+
+ expect(hashTable.buckets[0].toString(stringifier)).toBe('c:earth');
+ expect(hashTable.buckets[1].toString(stringifier)).toBe('a:sky,d:ocean');
+ expect(hashTable.buckets[2].toString(stringifier)).toBe('b:sea');
+
+ expect(hashTable.get('a')).toBe('sky');
+ expect(hashTable.get('d')).toBe('ocean');
+ expect(hashTable.get('x')).toBeNull();
+
+ hashTable.delete('a');
+
+ expect(hashTable.delete('not-existing')).toBeNull();
+
+ expect(hashTable.get('a')).toBeNull();
+ expect(hashTable.get('d')).toBe('ocean');
+
+ hashTable.set('d', 'ocean-new');
+ expect(hashTable.get('d')).toBe('ocean-new');
+ });
+});