Last active
September 17, 2016 20:26
-
-
Save khaled0fares/4e93109a8b925b3207b0d03368d6a87e to your computer and use it in GitHub Desktop.
Hash table implementation in JS
This file contains 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
let LinkedList = require('./linked_list'); | |
class HashTable{ | |
constructor(size){ | |
this.table = new Array(size); | |
} | |
_setup(key, index,head){ | |
let obj = {}; | |
obj[key] = head; | |
this.table[index] = new LinkedList(obj); | |
} | |
_hash(key){ | |
let total = 0, key_len = key.length,table_len = this.table.length; | |
const HORNER_CONSTANT = 37; | |
for(let i = 0; i < key_len; i++){ | |
total += total * HORNER_CONSTANT + key.charCodeAt(i); | |
} | |
return total % table_len; | |
} | |
_list(key){ | |
let index = this._hash(key); | |
return this.table[index]; | |
} | |
put(key, val){ | |
if(this.get(key)){return false;} | |
let index = this._hash(key), list = this.table[index]; | |
if(this.table[index] != undefined && this.table[index].head != null){ | |
let obj = {}; | |
obj[key] = val; | |
list.insertWithIndex(0,obj); | |
}else{ | |
this._setup(key, index, val); | |
} | |
} | |
get(key){ | |
let ele = this._list(key); | |
if(ele != undefined){ | |
let node = ele.findByKey(key); | |
return node.val[key]; | |
} | |
} | |
update(key, val){ | |
let ele = this._list(key) | |
if(ele != undefined){ | |
return ele.updateByKey(key, val); | |
} | |
} | |
remove(key){ | |
let ele = this._list(key) | |
if(ele != undefined){ | |
ele.removeByKey(key) | |
} | |
} | |
displayAll(){ | |
let i = 0, len = this.table.length; | |
for(i; i < len; i++){ | |
let ele = this.table[i]; | |
if(ele != undefined){ | |
ele.displayByKey(); | |
} | |
} | |
} | |
} | |
This file contains 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
class Node{ | |
constructor(val){ | |
this.val = val; | |
this.next = null | |
} | |
} | |
module.exports = class LinkedList{ | |
constructor(valOfHead){ | |
this.head = new Node(valOfHead); | |
this.length = 1; | |
} | |
exist(val){ | |
return !!this.find(val); | |
} | |
find(val){ | |
let currentNode = this.head; | |
while(currentNode != null){ | |
if(currentNode.val == val){ | |
return currentNode; | |
} | |
currentNode = currentNode.next; | |
} | |
return false; | |
} | |
findByKey(key){ | |
let currentNode = this.head; | |
while(currentNode != null){ | |
if(key in currentNode.val){ | |
return currentNode; | |
} | |
currentNode = currentNode.next; | |
} | |
return false; | |
} | |
updateByKey(key, val){ | |
let currentNode = this.head; | |
while(currentNode != null){ | |
if(key in currentNode.val){ | |
currentNode.val[key] = val; | |
} | |
currentNode = currentNode.next; | |
} | |
return false; | |
} | |
insert(newElement, afterElement){ | |
let newNode = new Node(newElement); | |
let afterNode = this.find(afterElement); | |
if(afterNode == false){console.log(`Element ${afterElement} doesn't exist`);return false;} | |
this.length += 1; | |
newNode.next = afterNode.next; | |
afterNode.next = newNode; | |
} | |
findPreviousNode(val){ | |
if(!this.exist(val)){console.log(`Element ${val} doesn't exist`);return false;} | |
let current = this.head; | |
while(current.next && current.next.val != val){ | |
current = current.next; | |
} | |
return current; | |
} | |
remove(val){ | |
//Element doesn't exist | |
if(!this.exist(val)){console.log(`Element ${val} doesn't exist`);return false}; | |
let removed = this.find(val); | |
//Element we want to remove is the first elment in the list | |
if(this.head.val == val){ | |
this.head = this.head.next; | |
} | |
//element exists But it's not the head element so we will remove it using it's previous node. | |
else{ | |
let prevNode = this.findPreviousNode(val); | |
prevNode.next = removed.next; | |
} | |
this.length -= 1; | |
return true; | |
} | |
findPreviousNodeByKey(key){ | |
let current = this.head; | |
while(current.next && key in current.next.val){ | |
current = current.next; | |
} | |
return current; | |
} | |
removeByKey(key){ | |
let removed = this.findByKey(key); | |
//Element we want to remove is the first elment in the list | |
if(key in this.head.val){ | |
this.head = this.head.next; | |
} | |
//element exists But it's not the head element so we will remove it using it's previous node. | |
else{ | |
let prevNode = this.findPreviousNodeByKey(key); | |
prevNode.next = removed.next; | |
} | |
this.length -= 1; | |
return true; | |
} | |
existWithIndex(index){return index < this.length && index >= 0;} | |
findByIndex(index){ | |
if(!this.existWithIndex(index)){console.log(`No node with Index ${index}`);return false;} | |
let currentNode = this.head; | |
let init = 0; | |
while(currentNode && init < index){ | |
currentNode = currentNode.next; | |
init += 1; | |
} | |
return currentNode; | |
} | |
insertWithIndex(index,item){ | |
let newNode = new Node(item); | |
//Element doesn't exist | |
if( !this.existWithIndex(index) ){ console.log(`Element with index ${index} doesn't exist`); return false;} | |
//Insert in the first position | |
if(index == 0){ | |
newNode.next = this.head; | |
this.head = newNode; | |
}else{ | |
//Insert between two nodes | |
let currentNode = this.findByIndex(index); | |
let prevNode = this.findPreviousNode(currentNode.val); | |
newNode.next = currentNode; | |
prevNode.next = newNode; | |
} | |
this.length += 1; | |
return true; | |
} | |
removeWithIndex(index){ | |
// if element doesn't exist | |
if(!this.existWithIndex(index)){console.log(`No element with index ${index} to be removed`);return false;} | |
// if it's the firts element in the list | |
if(index == 0){this.head = this.head.next;} | |
else{ | |
let removed = this.findByIndex(index); | |
let prevNode = this.findPreviousNode(removed.val); | |
prevNode.next = removed.next; | |
} | |
this.length -= 1; | |
return true; | |
} | |
displayByKey(){ | |
let current = this.head; | |
while(current){ | |
for(let key in current.val){ | |
console.log(`${key} -> ${current.val[key]}` ); | |
} | |
current = current.next; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment