Skip to content

Commit 094e1ba

Browse files
authored
Merge pull request knaxus#160 from knaxus/hash-table
added Hash Table
2 parents a47787d + ea7853e commit 094e1ba

File tree

5 files changed

+246
-2
lines changed

5 files changed

+246
-2
lines changed

README.md

+9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ This repo contains the following sections implemented in **JavaScript**
2626

2727
Find the detailed contents and problem list here: [Table Of Contents](TOC.md)
2828

29+
## Contributors
30+
31+
| Name | Twitter | LinkedIn | Website |
32+
| ----------------------------------------- | ------------------------------------------- | --------------------------------------------- | ------------------------------------------ |
33+
| [Ashok Dey](https://github.com/ashokdey) | [ashokdey\_](https://twitter.com/ashokdey_) | [Ashok Dey](https://linkedin.com/in/ashokdey) | [https://ashokdey.in](https://ashokdey.in) |
34+
| [Ashu Deshwal](https://github.com/TheSTL) | [\_TheSTL\_](https://twitter.com/_TheSTL_) | - | - |
35+
36+
[Detailed list of contributors](https://github.com/knaxus/problem-solving-javascript/graphs/contributors)
37+
2938
## Contribution Guide
3039

3140
It's great to know that you want to contribute to this repo. Thanks for taking interest. please fing the [guide here](https://github.com/knaxus/problem-solving-javascript/blob/master/CONTRIBUTING.md)

TOC.md

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
- Problems
5050
- [K Largest Elements](src/_DataStructures_/Heaps/k-largest-in-array)
5151
- [K Smallest Elements](src/_DataStructures_/Heaps/k-smallest-in-array)
52+
- [Hash Table](src/_DataStructures_/HashTable)
5253

5354
### Logical Problems
5455

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class HashEntry {
2+
constructor({ key, value }) {
3+
this.key = key;
4+
this.value = value;
5+
this.next = null;
6+
}
7+
}
8+
9+
module.exports = HashEntry;
+225
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
const HashEntry = require('./HashEntry');
2+
3+
class HashTable {
4+
constructor(slots, { allowResize = true, strongHash = true, custonHash = null }) {
5+
// init with a default set of slots
6+
this.slot = slots || 19;
7+
// size to hold the current size
8+
// and help to resize when the table is half filled
9+
this.size = 0;
10+
// threshold (let it be 70%)
11+
this.threshold = 0.7;
12+
// the main bucket
13+
this.bucket = new Array(this.slot);
14+
this.allowResize = allowResize;
15+
this.strongHash = strongHash;
16+
if (custonHash) {
17+
// eslint-disable-next-line no-underscore-dangle
18+
this._hash = custonHash;
19+
}
20+
21+
// fill the bucket with null
22+
for (let i = 0; i < this.slot; i += 1) this.bucket[i] = null;
23+
}
24+
25+
_hash(key) {
26+
// convert the key to String;
27+
const stringKey = String(key);
28+
29+
let index = 0;
30+
const PRIME_MULTIPLIER = 1801; // Random prime number
31+
const PRIME_ADDER = 2029; // Random prime number
32+
33+
// loop till the length of the key or max 100
34+
const loopTill = Math.min(stringKey.length, 100);
35+
36+
for (let i = 0; i < loopTill; i += 1) {
37+
const char = stringKey[i];
38+
const value = char.charCodeAt(0) - 96;
39+
index = (index * PRIME_MULTIPLIER + value) % this.bucket.length;
40+
if (this.strongHash) {
41+
index = (index + PRIME_ADDER) % this.bucket.length;
42+
}
43+
}
44+
return index;
45+
}
46+
47+
_resize() {
48+
const oldSlot = this.slot;
49+
const oldBucket = this.bucket;
50+
51+
this.slot = oldSlot * 2;
52+
const newBucket = new Array(this.slot);
53+
// fill the new bucket with nulls
54+
for (let i = 0; i < this.slot; i += 1) newBucket[i] = null;
55+
56+
this.bucket = newBucket;
57+
58+
for (let i = 0; i < oldSlot; i += 1) {
59+
if (oldBucket[i]) {
60+
let head = oldBucket[i];
61+
62+
while (head !== null) {
63+
const { key, value } = head;
64+
// eslint-disable-next-line no-underscore-dangle
65+
const newIndex = this._hash(key);
66+
// eslint-disable-next-line no-underscore-dangle
67+
this._push(newIndex, { key, value });
68+
head = head.next;
69+
}
70+
}
71+
}
72+
}
73+
74+
_push(index, value) {
75+
/**
76+
* Utility to add a SLL to the index in case of more than one
77+
* key hashes to the same index
78+
*/
79+
const node = new HashEntry(value);
80+
if (!this.bucket[index]) {
81+
this.bucket[index] = node;
82+
this.size += 1;
83+
return index;
84+
}
85+
86+
let head = this.bucket[index];
87+
// extract the key and see if it already exists
88+
const { key, value: newValue } = value;
89+
90+
// traverse to the end
91+
while (head.next !== null) {
92+
if (head.key === key) {
93+
// overridet the value with the new value
94+
head.value = newValue;
95+
return index;
96+
}
97+
head = head.next;
98+
}
99+
// if the key was not found
100+
head.next = node;
101+
this.size += 1;
102+
return index;
103+
}
104+
105+
_value(index, key) {
106+
let head = this.bucket[index];
107+
while (head !== null) {
108+
if (head.key === key) {
109+
return head.value;
110+
}
111+
head = head.next;
112+
}
113+
return null;
114+
}
115+
116+
// eslint-disable-next-line class-methods-use-this
117+
_convertNodesToSLL(nodeCollection) {
118+
// convert collection of nodes into a SLL
119+
let head = nodeCollection[0];
120+
const start = head;
121+
let i = 1;
122+
while (i < nodeCollection.length) {
123+
head.next = nodeCollection[i];
124+
i += 1;
125+
head = head.next;
126+
}
127+
128+
return start;
129+
}
130+
131+
set(key, value) {
132+
// eslint-disable-next-line no-underscore-dangle
133+
const index = this._hash(key);
134+
// storing value as an key-value pair
135+
// eslint-disable-next-line no-underscore-dangle
136+
this._push(index, { key, value });
137+
138+
/**
139+
* calculate the load factor, if it's greater than threshold
140+
* resize the hash table
141+
*/
142+
const loadFactor = Number((this.size / this.slot).toFixed(1));
143+
if (loadFactor > this.threshold && this.allowResize) {
144+
// console.log('Resizing hash table');
145+
// eslint-disable-next-line no-underscore-dangle
146+
this._resize();
147+
}
148+
}
149+
150+
get(key) {
151+
// get the index for the given key
152+
// eslint-disable-next-line no-underscore-dangle
153+
const index = this._hash(key);
154+
if (!this.bucket[index]) return null;
155+
// eslint-disable-next-line no-underscore-dangle
156+
return this._value(index, key);
157+
}
158+
159+
remove(key) {
160+
// get the index
161+
// eslint-disable-next-line no-underscore-dangle
162+
const index = this._hash(key);
163+
164+
// get the SLL using the index
165+
let head = this.bucket[index];
166+
// return null if the head is null
167+
if (!head) {
168+
return null;
169+
}
170+
171+
if (head.key === key) {
172+
let node = head;
173+
this.bucket[index] = head.next;
174+
const val = { key, value: node.value };
175+
node = null;
176+
this.size -= 1;
177+
return val;
178+
}
179+
180+
let previous = null;
181+
182+
while (head !== null) {
183+
if (head.key === key) {
184+
let node = head;
185+
previous.next = head.next;
186+
this.size -= 1;
187+
const res = { key, value: node.value };
188+
node = null;
189+
return res;
190+
}
191+
previous = head;
192+
head = head.next;
193+
}
194+
return null;
195+
}
196+
197+
getSize() {
198+
return this.size;
199+
}
200+
201+
isEmpty() {
202+
return this.size === 0;
203+
}
204+
}
205+
206+
// const ht = new HashTable(5, { allowResize: false, strongHash: false });
207+
// ht.set('maroon', 'I maroon');
208+
// ht.set('hello', 'I am a new value');
209+
// console.log(ht.bucket);
210+
// ht.set('hell', 'Bad value');
211+
// ht.set('hello', 'I am a yet another value');
212+
// ht.set('yellow', 'I am yellow');
213+
214+
// console.log(ht.get('hello'));
215+
// console.log(ht.get('maroon'));
216+
// console.log(ht.bucket);
217+
218+
// console.log('deleting hello........');
219+
// console.log(ht.remove('hello'));
220+
// console.log(ht.bucket);
221+
222+
// console.log(ht.remove('yellow'));
223+
// console.log(ht.bucket);
224+
225+
module.exports = HashTable;

src/_DataStructures_/LinkedList/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
// do not change the node class, you never know how many things it caan break! :)
1+
// do not change the node class, you never know how many things it caan break! :)
22
class Node {
33
constructor(data, next) {
44
this.data = data;
5-
this.next = next;
5+
this.next = next || null;
66
}
77
}
88

0 commit comments

Comments
 (0)