Hashing: Separate chaining with linked list in javascript - javascript

/*****************************************************
LIST
*****************************************************/
function Node(element) {
// store the node's data
this.element = element;
// store a link to the next node in the linked list
this.next = null;
}
function LList() {
this.head = new Node("head");
this.find = find;
this.insert = insert;
this.display = display;
this.findPrevious = findPrevious;
this.remove = remove;
}
function find(item) {
var currNode = this.head;
while(currNode.element != item) {
currNode = currNode.next;
}
return currNode;
}
function insert(newElement) {
var newNode = new Node(newElement);
var current = this.find("head");
newNode.next = current.next;
current.next = newNode;
}
function display(list) {
var currNode = this.head.next;
while (currNode != null) {
console.log(currNode.element);
currNode = currNode.next;
}
}
function findPrevious(item) {
var currNode = this.head;
while((currNode.next != null) && (currNode.next.element != item)) {
currNode = currNode.next;
}
return currNode;
}
function remove(item) {
var prevNode = this.findPrevious(item);
if (prevNode.next != null) {
prevNode.next = prevNode.next.next;
}
}
/*****************************************************
Hash Table
*****************************************************/
function HashTable() {
this.table = new Array(137);
this.betterHash = betterHash;
this.showDistro = showDistro;
this.put = put;
this.get = get;
this.buildChains = buildChains;
}
function put(key) {
var pos = this.betterHash(key);
this.table[pos].insert(key);
}
function get(key) {
var pos = this.betterHash(key);
return this.table[pos].find(key).element;
}
function betterHash(key) {
var constant = 37;
var total = 0;
for (var i = 0; i < key.length; i++) {
total += constant * total + key.charCodeAt(i);
}
total = total % this.table.length;
if(total < 0) {
total += this.table.length - 1;
}
return parseInt(total, 10);
}
function showDistro() {
for(var i = 0; i < this.table.length; i++) {
var currNode = this.table[i].head.next;
while (currNode != null) {
console.log(currNode.element);
currNode = currNode.next;
}
}
}
function buildChains() {
for (var i = 0; i < this.table.length; i++) {
this.table[i] = new LList();
}
}
var hTable = new HashTable();
hTable.buildChains();
var someNames = ["David", "Jennifer", "Donnie", "Raymond",
"Cynthia", "Mike", "Clayton", "Danny", "Jonathan"];
for(var i = 0; i < someNames.length; i++) {
hTable.put(someNames[i]);
}
hTable.showDistro();
hTable.get("David"); // "David"
I built a separate chaining by using both linked list and hash table in javascript. I was reading this book "Data structure and algorithm in javascript". But this author made a lot of mistakes and I think he doesn't really know about javascript. I modified his codes a lot. But since JavaScript is my first programming language and also this is my first time to learn data structure and algorithm, so I am not sure if I build it right.
Please explain how to modify or rebuild these codes again!

Related

Trouble finding the height of my first NON Binary Tree in JS

Here is the constructor function as well as the 'add' method...
function Tree(value) {
this.value = value;
this.children = [];
}
Tree.prototype.add = function(...value) {
if (Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
let node = new Tree;
node.value = value[i];
this.children[this.children.length] = node;
}
return;
}
let node = new Tree;
node.value = value;
this.children[this.children.length] = node;
};
Here is the 'height' method I am working on...
Tree.prototype.height = function() {
let height = 0;
if (this.children != null) {
if (this.children.length == 0) {
return height;
} else {
for (let i = 0; i < this.children.length; i++) {
height = Math.max(height, this.height(this.children[i]));
}
return depth + 1;
}
return height;
}
};
I am unsure of why I am getting "RangeError: Maximum call stack size exceeded" because the method should return height if the children array length is 0.
Here are the test cases I am using...
tree = new Tree();
tree.add(5);
tree.add(8);
var son = tree.children[0];
son.add(1);
son.add(4);
var daughter = tree.children[0];
daughter.add(10);
var grandson = son.children[1];
grandson.add(3);
grandson.height() //should return 1
tree.height() //should return
Any tips on how to fix my infinite loop will be greatly appreciated. Thank you for your time!

Get a value of a HashTable

I was making a HashTable to have as an example and have it saved for any problem, but I ran into a problem trying to implement a method that returns true or false in case the value belongs to the HashTable, since it is inside a arrays of objects as comment in the code.
I have tried for loops, .map and for of, but it always fails, if someone could help me.
function HashTable () {
this.buckets = [];
this.numbuckets = 35;
}
HashTable.prototype.hash = function (key) {
let suma = 0;
for (let i = 0; i < key.length; i++) {
suma = suma + key.charCodeAt(i);
}
return suma % this.numbuckets;
}
HashTable.prototype.set = function (key, value) {
if (typeof key !== "string") {
throw new TypeError ("Keys must be strings")
} else {
var index = this.hash(key);
if(this.buckets[index] === undefined) {
this.buckets[index] = {};
}
this.buckets[index][key] = value;
}
}
HashTable.prototype.get = function (key) {
var index = this.hash(key);
return this.buckets[index][key];
}
HashTable.prototype.hasKey = function (key) {
var index = this.hash(key);
return this.buckets[index].hasOwnProperty(key)
}
HashTable.prototype.remove = function (key) {
var index = this.hash(key);
if (this.buckets[index].hasOwnProperty(key)) {
delete this.buckets[index]
return true;
}
return false;
}
HashTable.prototype.hasValue = function (value) {
let result = this.buckets;
result = result.flat(Infinity);
return result // [{Name: Toni}, {Mame: Tino}, {Answer: Jhon}]
}
You can use Object.values() to get the values of all the propertyies in the bucket.
function HashTable() {
this.buckets = [];
this.numbuckets = 35;
}
HashTable.prototype.hash = function(key) {
let suma = 0;
for (let i = 0; i < key.length; i++) {
suma = suma + key.charCodeAt(i);
}
return suma % this.numbuckets;
}
HashTable.prototype.set = function(key, value) {
if (typeof key !== "string") {
throw new TypeError("Keys must be strings")
} else {
var index = this.hash(key);
if (this.buckets[index] === undefined) {
this.buckets[index] = {};
}
this.buckets[index][key] = value;
}
}
HashTable.prototype.get = function(key) {
var index = this.hash(key);
return this.buckets[index][key];
}
HashTable.prototype.hasKey = function(key) {
var index = this.hash(key);
return this.buckets[index].hasOwnProperty(key)
}
HashTable.prototype.remove = function(key) {
var index = this.hash(key);
if (this.buckets[index].hasOwnProperty(key)) {
delete this.buckets[index]
return true;
}
return false;
}
HashTable.prototype.hasValue = function(value) {
return this.buckets.some(bucket => Object.values(bucket).includes(value));
}
let h = new HashTable;
h.set("Abc", 1);
h.set("Def", 2);
console.log(h.hasValue(1));
console.log(h.hasValue(3));

Calling a Method on a Linked List inside of Javascript implementation of a Hash Table

I'm working on creating a Hash Table in Javascript to better understand the data structure. I implemented it with a Linked List at each table position to deal with conflicts.
The problem is that I cannot call .add on this.storage[index], as it is undefined. When I log this.storage[index] I see my head nodes in my linked list and the methods that I need. So I'm not sure what the problem is.
var Node = function(key, value) {
this.key = key;
this.value = value;
this.next = null;
};
var LinkedList = function() {
this.head = new Node('head');
this.add = function(key, value) {
var node = new Node(key, value);
var curNode = this.head;
while (curNode.next !== null) {
curNode = curNode.next;
}
curNode.next = node;
};
this.find = function(key) {
var curNode = this.head;
while (curNode.key !== key && curNode.next !== null) {
curNode = curNode.next;
}
return curNode.value;
};
};
var HashTable = function(max) {
this.max = max;
this.storage = [];
for (var i = 0; i < max; ++i) {
this.storage[i] = new LinkedList();
}
this.hash = function(key) {
var sum = 0;
for (var i = 0; i < key.length; ++i) {
sum += key[i].charCodeAt() - 97;
}
return sum % this.max;
};
this.addValue = function(key, value) {
var index = this.hash(key);
this.storage[index].add(key, value);
};
this.getValue = function(key) {
var index = this.hash(key);
return this.storage[index].find(key);
};
};
var hash = new HashTable(5);
hash.addValue("I");
hash.addValue("would");
hash.addValue("like");
hash.addValue("coffee");
hash.getValue('I');
The Javascript modulus operator doesn't work as you might expect for negative numbers. If sum is -4, sum % max is not max - 4, it's -4. Then you try to add to this.storage[-4], which is undefined. You need to check for this and adjust.
var Node = function(key, value) {
this.key = key;
this.value = value;
this.next = null;
};
var LinkedList = function() {
this.head = new Node('head');
this.add = function(key, value) {
var node = new Node(key, value);
var curNode = this.head;
while (curNode.next !== null) {
curNode = curNode.next;
}
curNode.next = node;
};
this.find = function(key) {
var curNode = this.head;
while (curNode.key !== key && curNode.next !== null) {
curNode = curNode.next;
}
return curNode.value;
};
};
var HashTable = function(max) {
this.max = max;
this.storage = [];
for (var i = 0; i < max; ++i) {
this.storage[i] = new LinkedList();
}
this.hash = function(key) {
var sum = 0;
for (var i = 0; i < key.length; ++i) {
sum += key[i].charCodeAt() - 97;
}
sum = sum % this.max;
if (sum < 0) {
sum = this.max + sum;
}
return sum;
};
this.addValue = function(key, value) {
var index = this.hash(key);
this.storage[index].add(key, value);
};
this.getValue = function(key) {
var index = this.hash(key);
return this.storage[index].find(key);
};
};
var hash = new HashTable(5);
hash.addValue("I");
hash.addValue("would");
hash.addValue("like");
hash.addValue("coffee");
hash.getValue('I');
console.log(hash);

How does Javascript evaluate the right parenthesis?

I'm working on a calculator that takes an expression such as (5+4) and evaluates it by passing the buttons pressed to an array, and then building a parse tree from the data in the array.
What's interesting/strange, is that my code won't push the value of the right parenthesis to the array. Here is my code, could someone help me out?
The console.log activeButton shows that is the value of the button being pressed, but even when I placed calcArray.push() outside the if statements it would not push ) to an array.
$(document).ready(function(){
var calcArray = new Array();
$("input").click(function(){
var activeButton = this.value;
console.log(activeButton);
if(!isNaN(activeButton))
{
calcArray.push(parseInt(activeButton));
console.log(calcArray);
}
else if(activeButton === "=")
{
evaluate(buildTree(calcArray));
calcArray = [];
}
else
{
calcArray.push(activeButton);
}
});
});
The BuildTree code:
function BinaryTree(root) {
this.root = root;
this.activeNode = root;
}
function Node(element){
this.element = element;
this.parent;
this.rightChild;
this.leftChild;
this.setLeft = function(node){
this.leftChild = node;
node.parent = this;
};
this.setRight = function(node){
this.rightChild = node;
node.parent = this;
};
}
//methods
var buildTree = function(array)
{
var tree = new BinaryTree(new Node(null));
for(var i = 0; i < array.length; i++)
{
var newNode = new Node(array[i]);
if(array[i] == "(")
{
newNode.element = null;
tree.activeNode.setLeft(newNode);
tree.activeNode = newNode;
}
else if(array[i] == "+" || array[i] == "-" || array[i] == "/" || array[i] == "*")
{
tree.activeNode.element = newNode.element;
tree.activeNode.setRight(new Node(null));
tree.activeNode = tree.activeNode.rightChild;
}
else if(array[i] == ")")
{
if(tree.activeNode.parent == null)
{
;
}
else
{
tree.activeNode = tree.activeNode.parent;
tree.root = tree.activeNode;
}
}
else
{
tree.activeNode.element = newNode.element;
tree.activeNode = tree.activeNode.parent;
}
}
return tree.activeNode;
}
var evaluate = function(node){
var newNode1, newNode2;
newNode1 = new Node(null);
newNode1.parent = node;
newNode2 = new Node(null);
newNode2.parent = node;
if(node.leftChild == null && node.rightChild == null)
return node.element;
else{
newNode1.element = evaluate(node.leftChild);
newNode2.element = evaluate(node.rightChild);
if(newNode1.parent.element == "+")
{
return Number(newNode1.element) + Number(newNode2.element);
}
if(newNode1.parent.element == "-")
{
return newNode1.element - newNode2.element;
}
if(newNode1.parent.element == "*")
{
return newNode1.element * newNode2.element;
}
else
{
return newNode1.element / newNode2.element;
}
}
};
I just tried this out using your code and it worked fine passing the value as a string:
function pushButton (value) {
var activeButton = value;
console.log(activeButton);
if(!isNaN(activeButton))
{
calcArray.push(parseInt(activeButton));
console.log(calcArray);
}
else if(activeButton === "=")
{
evaluate(buildTree(calcArray));
calcArray = [];
}
else
{
calcArray.push(activeButton);
}
};
You aren't ever printing out the array in the last case (which is where the right paren would go), so are you sure it's not on the array and you just aren't seeing the visual feedback?
If so, we need to see more of your code. Try and setup a jsfiddle.

XML Javascript undefined error in ie9

I have a 'jargon buster' on my site that uses an xml file to load an A-Z of words which when clicked display a brief short explanation of each word. This works fine in all browsers bar the latest ie's which i get an 'undefined' error with. The jscript im using is below
Jargon = {
xmlfile: 'http://www.mysite.com/jargon.xml',
xml: null,
wordHolder: 'words',
defHolder: 'definition',
idprefix: 'jargon_',
selected: null,
init: function () {
var con = Jargon.xhcon();
Jargon.wordHolder = $(Jargon.wordHolder);
Jargon.defHolder = $(Jargon.defHolder);
if (!con || !Jargon.wordHolder || !Jargon.defHolder) {
return;
}
function conComplete(oXML) {
Jargon.xml = oXML.responseXML;
//Jargon.showWords('a');
}
con.connect(Jargon.xmlfile, 'GET', Math.random(), conComplete);
},
showWords: function (c) {
if (Jargon.selected) {
Jargon.selected.className = '';
}
var words = Jargon.getWords(c);
while (Jargon.wordHolder.childNodes.length > 0) {
Jargon.wordHolder.removeChild(Jargon.wordHolder.childNodes[0]);
}
while (Jargon.defHolder.childNodes.length > 0) {
Jargon.defHolder.removeChild(Jargon.defHolder.childNodes[0]);
}
for (var i = 0; i < words.length; i++) {
var o = document.createElement('a');
o.href = 'javascript:Jargon.showDef(\'' + words[i].id + '\');';
o.id = Jargon.idprefix + words[i].id;
//o.onclick = Jargon.showDef;
o.appendChild($t(words[i].name));
Jargon.wordHolder.appendChild(o);
Jargon.wordHolder.appendChild(document.createElement('br'));
}
if (!words.length) {
var o = document.createElement('p');
var s = 'There are no words for the letter ' + c.toUpperCase();
Jargon.wordHolder.appendChild(o.appendChild($t(s)));
}
},
showDef: function (id) {
var o = $(Jargon.idprefix + id);
if (Jargon.selected) {
Jargon.selected.className = '';
}
if (o) {
o.className = 'selected';
Jargon.selected = o;
}
var defobjs = Jargon.getDef(id);
while (Jargon.defHolder.childNodes.length > 0) {
Jargon.defHolder.removeChild(Jargon.defHolder.childNodes[0]);
}
var heading = document.createElement('span');
heading.className = "jargtitle";
heading.appendChild(document.createTextNode(defobjs[1][0].textContent));
Jargon.defHolder.appendChild(heading);
var definition = document.createElement('span');
definition.className = "jargdefinition";
definition.appendChild(document.createTextNode(defobjs[0][0].textContent));
Jargon.defHolder.appendChild(definition);
},
getWords: function(c) {
var x = Jargon.xml;
var letters = x.getElementsByTagName('letter');
var oLetter = null;
for (var i = 0; i < letters.length; i++) {
if (letters[i].getAttribute('id') == c) {
oLetter = letters[i];
break;
}
}
if (!oLetter) {
return [];
}
var words = [];
for (i = 0; i < oLetter.childNodes.length; i++) {
var oJargon = oLetter.childNodes[i];
if (oJargon.nodeName == 'jargon') {
var s = Jargon.getName(oJargon);
words[words.length] = {
id: oLetter.childNodes[i].getAttribute('id'),
name: s
};
}
}
return words;
},
getDef: function (id) {
var x = Jargon.xml;
var j = null;
var temp = new Array(2);
var jargons = x.getElementsByTagName('jargon');
for (var i = 0; i < jargons.length; i++) {
if (jargons[i].getAttribute('id') == id) {
j = jargons[i];
break;
}
}
if (!j) {
return [];
}
//return [];
for (i = 0; i < j.childNodes.length; i++) {
if (j.childNodes[i].nodeName == 'name') {
temp[1] = j.childNodes[i].childNodes;
}
}
for (i = 0; i < j.childNodes.length; i++) {
if (j.childNodes[i].nodeName == 'desc') {
temp[0] = j.childNodes[i].childNodes;
}
}
//return [];
return temp;
},
cloneNode: function (oldNode, deep) {
deep = (deep) ? true : false;
// a replacement to the normal dom clone node
// this will copy xml nodes to html nodes
// which can then be inserted into the document
// scope in all browsers
// See for for the bug http://www.quirksmode.org/blog/archives/2005/12/xmlhttp_notes_c.html
var newNode = null;
if (oldNode.nodeType == '3') {
// textnode
newNode = $t(oldNode.nodeValue);
}
else if (oldNode.nodeType == '1') {
// element node
newNode = document.createElement(oldNode.nodeName);
if (deep) {
for (var i = 0; i < oldNode.childNodes.length; i++) {
newNode.appendChild(Jargon.cloneNode(oldNode.childNodes[i], true));
}
}
}
return newNode;
},
getName: function (oJargon) {
for (var i = 0; i < oJargon.childNodes.length; i++) {
if (oJargon.childNodes[i].nodeName == 'name') {
var oName = oJargon.childNodes[i];
var s = '';
for (var j = 0; j < oName.childNodes.length; j++) {
if (oName.childNodes[j].nodeType == 3) {
// text node
s += oName.childNodes[j].nodeValue;
}
}
return s;
}
}
return '';
},
xhcon: function () {
var xmlhttp, bComplete = false;
try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); }
catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
catch (e) { try { xmlhttp = new XMLHttpRequest(); }
catch (e) { xmlhttp = false; }}}
if (!xmlhttp) {
return null;
}
this.connect = function(sURL, sMethod, sVars, fnDone) {
if (!xmlhttp) {
return false;
}
bComplete = false;
sMethod = sMethod.toUpperCase();
try {
if (sMethod == "GET") {
xmlhttp.open(sMethod, sURL+"?"+sVars, true);
sVars = "";
}
else {
xmlhttp.open(sMethod, sURL, true);
xmlhttp.setRequestHeader("Method", "POST "+sURL+" HTTP/1.1");
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && !bComplete) {
bComplete = true;
fnDone(xmlhttp);
}
};
xmlhttp.send(sVars);
}
catch(z) { return false; }
return true;
};
return this;
}
}
In terms of how im calling the jscript im using <li>a</li>
which loads a list of all items that begin with f then when i click one of items from that list say "Fiduciary" it triggers javascript:Jargon.showDef('f1'); which in turns loads the and into a definition div
however in ie9 it displays "undefined" . It works in all other browers
Example of the XML below:
<letter id="f"> -<jargon id="f1"> <name>Fiduciary</name> <desc>in a position of trust. This includes people such as trustees looking after trust assets for the beneficiaries and company directors running a company for the shareholders' benefit.</desc> </jargon> -<jargon id="f2"> <name>Forfeiture</name> <desc>the loss of possession of a property because the tenancy conditions have not been met by the tenant.</desc> </jargon> -<jargon id="f3"> <name>Freehold</name> <desc>describing land that only the owner has any rights over.</desc> </jargon> -<jargon id="f4"> <name>Free of encumbrances</name> <desc>no one else having any rights over something. When property is owned by someone and nobody else has any rights over it, it is owned free of encumbrances.</desc> </jargon> </letter>

Categories

Resources