-
Notifications
You must be signed in to change notification settings - Fork 269
added Hash Table #160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
added Hash Table #160
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
d221391
update: initial skeleton for Hash Table
ashokdey bd73d1f
update: change in the Node structure
ashokdey ae5ea99
update: added rehashing to avoid collision
ashokdey 44c158a
fixes: better hash function, improved comments
ashokdey 62c6b71
update: change in threshold value
ashokdey 7ff8276
update: entry in README
ashokdey 22c6465
update: added list of contributors
ashokdey 2060a13
update: delete key of hash table
ashokdey 3a09fef
fix: renamed to remove()
ashokdey 02fec4f
update: options added to refect corner case testing
ashokdey 3c45b0b
update: implementation of remove()
ashokdey cffd6e2
update: remove() logic change
ashokdey ea7853e
update: override the value for same key
ashokdey File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
src/_DataStructures_/HashTable/HashEntry.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
class HashEntry { | ||
constructor({ key, value }) { | ||
this.key = key; | ||
this.value = value; | ||
this.next = null; | ||
} | ||
} | ||
|
||
module.exports = HashEntry; |
225 changes: 225 additions & 0 deletions
src/_DataStructures_/HashTable/index.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
const HashEntry = require('./HashEntry'); | ||
|
||
class HashTable { | ||
constructor(slots, { allowResize = true, strongHash = true, custonHash = null }) { | ||
// init with a default set of slots | ||
this.slot = slots || 19; | ||
// size to hold the current size | ||
// and help to resize when the table is half filled | ||
this.size = 0; | ||
// threshold (let it be 70%) | ||
this.threshold = 0.7; | ||
// the main bucket | ||
this.bucket = new Array(this.slot); | ||
this.allowResize = allowResize; | ||
this.strongHash = strongHash; | ||
if (custonHash) { | ||
// eslint-disable-next-line no-underscore-dangle | ||
this._hash = custonHash; | ||
} | ||
|
||
// fill the bucket with null | ||
for (let i = 0; i < this.slot; i += 1) this.bucket[i] = null; | ||
} | ||
|
||
_hash(key) { | ||
// convert the key to String; | ||
const stringKey = String(key); | ||
|
||
let index = 0; | ||
const PRIME_MULTIPLIER = 1801; // Random prime number | ||
const PRIME_ADDER = 2029; // Random prime number | ||
|
||
// loop till the length of the key or max 100 | ||
const loopTill = Math.min(stringKey.length, 100); | ||
|
||
for (let i = 0; i < loopTill; i += 1) { | ||
const char = stringKey[i]; | ||
const value = char.charCodeAt(0) - 96; | ||
index = (index * PRIME_MULTIPLIER + value) % this.bucket.length; | ||
if (this.strongHash) { | ||
index = (index + PRIME_ADDER) % this.bucket.length; | ||
} | ||
} | ||
return index; | ||
} | ||
|
||
_resize() { | ||
const oldSlot = this.slot; | ||
const oldBucket = this.bucket; | ||
|
||
this.slot = oldSlot * 2; | ||
const newBucket = new Array(this.slot); | ||
// fill the new bucket with nulls | ||
for (let i = 0; i < this.slot; i += 1) newBucket[i] = null; | ||
|
||
this.bucket = newBucket; | ||
|
||
for (let i = 0; i < oldSlot; i += 1) { | ||
if (oldBucket[i]) { | ||
let head = oldBucket[i]; | ||
|
||
while (head !== null) { | ||
const { key, value } = head; | ||
// eslint-disable-next-line no-underscore-dangle | ||
const newIndex = this._hash(key); | ||
// eslint-disable-next-line no-underscore-dangle | ||
this._push(newIndex, { key, value }); | ||
head = head.next; | ||
} | ||
} | ||
} | ||
} | ||
|
||
_push(index, value) { | ||
/** | ||
* Utility to add a SLL to the index in case of more than one | ||
* key hashes to the same index | ||
*/ | ||
const node = new HashEntry(value); | ||
if (!this.bucket[index]) { | ||
this.bucket[index] = node; | ||
this.size += 1; | ||
return index; | ||
} | ||
|
||
let head = this.bucket[index]; | ||
// extract the key and see if it already exists | ||
const { key, value: newValue } = value; | ||
|
||
// traverse to the end | ||
while (head.next !== null) { | ||
if (head.key === key) { | ||
// overridet the value with the new value | ||
head.value = newValue; | ||
return index; | ||
} | ||
head = head.next; | ||
} | ||
// if the key was not found | ||
head.next = node; | ||
this.size += 1; | ||
return index; | ||
} | ||
|
||
_value(index, key) { | ||
let head = this.bucket[index]; | ||
while (head !== null) { | ||
if (head.key === key) { | ||
return head.value; | ||
} | ||
head = head.next; | ||
} | ||
return null; | ||
} | ||
|
||
// eslint-disable-next-line class-methods-use-this | ||
_convertNodesToSLL(nodeCollection) { | ||
// convert collection of nodes into a SLL | ||
let head = nodeCollection[0]; | ||
const start = head; | ||
let i = 1; | ||
while (i < nodeCollection.length) { | ||
head.next = nodeCollection[i]; | ||
i += 1; | ||
head = head.next; | ||
} | ||
|
||
return start; | ||
} | ||
|
||
set(key, value) { | ||
// eslint-disable-next-line no-underscore-dangle | ||
const index = this._hash(key); | ||
// storing value as an key-value pair | ||
// eslint-disable-next-line no-underscore-dangle | ||
this._push(index, { key, value }); | ||
|
||
/** | ||
* calculate the load factor, if it's greater than threshold | ||
* resize the hash table | ||
*/ | ||
const loadFactor = Number((this.size / this.slot).toFixed(1)); | ||
if (loadFactor > this.threshold && this.allowResize) { | ||
// console.log('Resizing hash table'); | ||
// eslint-disable-next-line no-underscore-dangle | ||
this._resize(); | ||
} | ||
} | ||
|
||
get(key) { | ||
// get the index for the given key | ||
// eslint-disable-next-line no-underscore-dangle | ||
const index = this._hash(key); | ||
if (!this.bucket[index]) return null; | ||
// eslint-disable-next-line no-underscore-dangle | ||
return this._value(index, key); | ||
} | ||
|
||
remove(key) { | ||
// get the index | ||
// eslint-disable-next-line no-underscore-dangle | ||
const index = this._hash(key); | ||
|
||
// get the SLL using the index | ||
let head = this.bucket[index]; | ||
// return null if the head is null | ||
if (!head) { | ||
return null; | ||
} | ||
|
||
if (head.key === key) { | ||
let node = head; | ||
this.bucket[index] = head.next; | ||
const val = { key, value: node.value }; | ||
node = null; | ||
this.size -= 1; | ||
return val; | ||
} | ||
|
||
let previous = null; | ||
|
||
while (head !== null) { | ||
if (head.key === key) { | ||
let node = head; | ||
previous.next = head.next; | ||
this.size -= 1; | ||
const res = { key, value: node.value }; | ||
node = null; | ||
return res; | ||
} | ||
previous = head; | ||
head = head.next; | ||
} | ||
return null; | ||
} | ||
|
||
getSize() { | ||
return this.size; | ||
} | ||
|
||
isEmpty() { | ||
return this.size === 0; | ||
} | ||
} | ||
|
||
// const ht = new HashTable(5, { allowResize: false, strongHash: false }); | ||
// ht.set('maroon', 'I maroon'); | ||
// ht.set('hello', 'I am a new value'); | ||
// console.log(ht.bucket); | ||
// ht.set('hell', 'Bad value'); | ||
// ht.set('hello', 'I am a yet another value'); | ||
// ht.set('yellow', 'I am yellow'); | ||
|
||
// console.log(ht.get('hello')); | ||
// console.log(ht.get('maroon')); | ||
// console.log(ht.bucket); | ||
|
||
// console.log('deleting hello........'); | ||
// console.log(ht.remove('hello')); | ||
// console.log(ht.bucket); | ||
|
||
// console.log(ht.remove('yellow')); | ||
// console.log(ht.bucket); | ||
|
||
module.exports = HashTable; |
4 changes: 2 additions & 2 deletions
src/_DataStructures_/LinkedList/index.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.