accessing a property of a node, javascript binary search tree - javascript

I'm new to nodeJS javascript and I have a simple problem here.
I have a Binary Search Tree (BST) in javascript. Each Node has a value, and a count. We're inserting words into the BST such that each Node represents a word. Upon insertion, if the word is already in the BST, we want to increase the count of that word, where count is a property on the Node.
My problem comes when I want to display the Nodes and their counts. Displaying the counts is not working correctly. That is, the BST.prototype.showWords = function (node) is not correct.
Thank you for your help and insight!!!
files:
bstnode.js - the 'node class'
BST.js - the Binary Search Tree Class
wordCount.js - reads in a text file, splits on spaces to get words, and creates nodes. I want each node to represent a word, and if that word appears multiple times, count++ on that node each time.
// wordCount.js
var BST = require('./bst.js');
var fs = require('fs');
var countNodes = require('./countNodes.js');
// THIS RIGHT HERE DOES NOT WORK CORRECTLY.
BST.prototype.showWords = function (node) {
if (node !== null) {
this.inOrder(node.left);
console.log(node.showCount());
this.inOrder(node.right);
}
};
// get the file, and get it into an array of string-words
var filePath = './simpleTest.txt';
var contents = fs.readFileSync(filePath).toString();
var stringArr = contents.split(' ');
var myBST = new BST();
for (var i=0; i<stringArr.length; i++){
var word = stringArr[i].trim();
var aNode = myBST.find(word);
console.log(aNode);
if ( aNode !== null ) { // then word exists in BST already,
aNode.count++; // node count ++ on that one
}
else { // then word dne in BST, so add it now!
myBST.insert(word);
}
}
myBST.showWords(myBST.root);
// bstnode.js
'use strict';
var Node = function (data, left, right) {
this.data = data;
this.count = 1;
this.left = left;
this.right = right;
};
Node.prototype.show = function () {
return this.data;
};
Node.prototype.show2 = function () {
return (this.data + ' ' + this.count);
};
module.exports = Node;
'use strict';
// bst.js - has the BST CTor function, and requires the bstnode in
var Node = require('./bstnode');
// BST CTor function
var BST = function() { // Binary Search Tree class
this.root = null;
};
BST.prototype.insert = function (data) {
var n = new Node(data, null, null);
if (this.root === null) {
this.root = n;
} else {
var current = this.root;
var parent;
while (true) {
parent = current;
if (data < current.data) {
current = current.left;
if (current === null) {
parent.left = n;
break;
}
} else {
current = current.right;
if (current === null) {
parent.right = n;
break;
}
}
}
}
};
// inOrder: log VALUES in order starting from node param
BST.prototype.inOrder = function (node) {
if (node !== null) {
this.inOrder(node.left);
console.log(node.show() + " ");
this.inOrder(node.right);
}
};
BST.prototype.find = function (data) {
var current = this.root;
while (current && current.data !== data) {
if (data < current.data) {
current = current.left;
} else {
current = current.right;
}
}
return current;
};
module.exports = BST;

a friend helped me out, here's the soln
// THIS RIGHT HERE -- - --
// That's because it should call itself recursively, not the inOrder function!
BST.prototype.showWords = function (node) {
if (node !== null) {
this.showWords(node.left);
console.log(node.showCount());
this.showWords(node.right);
}
};

Related

toString method on Linked List implementation not working in js

I'm working through Cracking the Coding Interview and I thought I'd implement all the data structures in JS 5. Can anyone explain to me why my toString method isn't working?
Thanks!
function Node(data) {
this.next = null;
this.data = data;
}
Node.prototype.appendToTail = function(data) {
var end = new Node(data);
var n = this;
while (n.next != null) {
n = n.next;
}
n.next = end;
}
Node.prototype.toString = function(head) {
console.log(head)
if (head == null) {
return ""
} else {
return head.data.toString() + "-> " + head.next.toString();
}
}
var ll = new Node(1);
ll.appendToTail(3);
ll.appendToTail(4);
console.log(ll.toString())
function Node(data) {
this.next = null;
this.data = data;
}
Node.prototype.appendToTail = function(data) {
var end = new Node(data);
var n = this;
while (n.next != null) {
n = n.next;
}
n.next = end;
};
Node.prototype.toString = function() {
var returnValue = String(this.data);
if (this.next) {
returnValue = returnValue + "-> " + String(this.next);
}
return returnValue;
};
var ll = new Node(1);
ll.appendToTail(3);
ll.appendToTail(4);
console.log(String(ll))
or avoid this kind of problems completly and do not use prototype, class, this, call, etc
Your toString function takes an argument, but you're not passing it when you call toString.
If you want to access the node, you should use this, instead of passing in a value
Node.prototype.toString = function() {
var result = this.data.toString();
if (this.next) {
result += "-> " + this.next.toString();
}
return result;
}

Extend Javascript Syntax to Add Typing

I'd like to extend javascript to add custom type checking.
e.g.
function test(welcome:string, num:integer:non-zero) {
console.log(welcome + num)
}
which would compile into:
function test(welcome, num) {
if(Object.prototype.toString.call(welcome) !== "[object String]") {
throw new Error('welcome must be a string')
}
if (!Number.isInteger(num)) {
throw new Error('num must be an integer')
}
console.log(welcome + num)
}
What's the most straightforward way of doing this?
So far i've looked at:
sweet.js (online documentation looks out of date as I think it's going through some sort of internal rewrite)
esprima and escodegen (not sure where to start)
manually parsing using regular expressons
After evaluating all the various options, using sweet.js appears to be the best solution. It's still fairly difficult to get working (and I am probably doing stuff the wrong way) but just in case someone want's to do something similar this here was my solution.
'use strict'
syntax function = function(ctx) {
let funcName = ctx.next().value;
let funcParams = ctx.next().value;
let funcBody = ctx.next().value;
//produce the normal params array
var normalParams = produceNormalParams(funcParams)
//produce the checks
var paramChecks = produceParamChecks(funcParams)
//produce the original funcBody code
//put them together as the final result
var params = ctx.contextify(funcParams)
var paramsArray = []
for (let stx of params) {
paramsArray.push(stx)
}
var inner = #``
var innerStuff = ctx.contextify(funcBody)
for (let item of innerStuff) {
inner = inner.concat(#`${item}`)
}
var result = #`function ${funcName} ${normalParams} {
${paramChecks}
${inner}
}`
return result
function extractParamsAndParamChecks(paramsToken) {
var paramsContext = ctx.contextify(paramsToken)
//extracts the actual parameters
var paramsArray = []
var i = 0;
var firstItembyComma = true
for (let paramItem of paramsContext) {
if (firstItembyComma) {
paramsArray.push({
param: paramItem,
checks: []
})
firstItembyComma = false
}
if (paramItem.value.token.value === ',') {
firstItembyComma = true
i++
} else {
paramsArray[i].checks.push(paramItem.value.token.value)
}
}
for (var i = 0; i < paramsArray.length; i++) {
var checks = paramsArray[i].checks.join('').split(':')
checks.splice(0, 1)
paramsArray[i].checks = checks
}
return paramsArray
}
function produceNormalParams(paramsToken) {
var paramsArray = extractParamsAndParamChecks(paramsToken)
//Produces the final params #string
var inner = #``
var first = true
for (let item of paramsArray) {
if (first === true) {
inner = inner.concat(#`${item.param}`)
} else {
inner = inner.concat(#`,${item.param}`)
}
}
return #`(${inner})`
}
function produceParamChecks(paramsToken) {
var paramsArray = extractParamsAndParamChecks(paramsToken)
var result = #``
for (let paramObject of paramsArray) {
var tests = produceChecks(paramObject)
result = result.concat(#`${tests}`)
}
return result
}
function produceChecks(paramObject) {
var paramToken = paramObject.param
var itemType = paramObject.checks[0]
var checks = paramObject.checks
if (itemType === undefined) return #``
if (itemType === 'array') {
return #`if (Object.prototype.toString.call(${paramToken}) !== "[object Array]") throw new Error('Must be array:' + ${paramToken})`
else {
throw new Error('item type not recognised: ' + itemType)
}
}
}

Recursion to traverse all the nested child nodes of Binary Tree Javascript

I am playing around with a binary tree. I am trying to use recursion to find all the nested children's values and push all the values into an array. I started with the left tree to see if it works. I tried to call childrenArray() but the console says childrenArray() is not defined. When I ask if (typeof BinaryTree.prototype.childrenArray === 'function'), it returns true. Please teach me and tell me why I wasn't able to execute my code?
var Tree = function(value) {
if (!(this instanceof Tree)) {
return new Tree(value);
}
this.value = value;
this.children = [];
};
Tree.prototype.addChild = function(value) {
var child = new Tree(value);
this.children.push(child);
};
Tree.prototype.contains = function(value) {
if (this.value === value) {
return true;
} else {
for (var i = 0; i < this.children.length; i++) {
if (this.children[i] && this.children[i].contains(value)) {
return true;
}
}
return false;
}
};
var BinaryTree = function(value) {
if (!(this instanceof BinaryTree)) {
return new BinaryTree(value);
}
Tree.call(this, value);
};
BinaryTree.prototype = Object.create(Tree.prototype);
BinaryTree.prototype.addChild = function(value) {
if (value < this.value) {
if (this.children[0] === undefined) {
this.children[0] = new BinaryTree(value);
}
this.children[0].addChild(value);
} else if (value > this.value) {
if (this.children[1] === undefined) {
this.children[1] = new BinaryTree(value);
}
this.children[1].addChild(value);
}
};
BinaryTree.prototype.contains = function(value) {
if (value < this.value) {
if (this.children[0] === undefined) {
return false;
}
return this.children[0].contains(value);
} else if (value > this.value) {
if (this.children[1] === undefined) {
return false;
}
return this.children[1].contains(value);
}
};
var a = new BinaryTree();
a.value = 10;
a.addChild(4);
a.addChild(11);
a.addChild(3);
BinaryTree.prototype.childrenArray = function() {
var results = [];
if (this.value) {
results.push(this.value);
}
if (this.children[0].length === 0) {
return results;
}
for (var i = 0; i < this.children[0].children.length; i++) {
if (this.children[i].value) {
results.push(this.children[i].value);
return this.childrenArray();
}
}
};
a.childrenArray();
As #melpomene mentioned, you are invoking childArray but you didn't define it anywhere. I assume the line return childArray(); ended up there by mistake, you probably meant to recursively return childrenArray for the left child of root.
I would like to mention that your loop itself (without the recursive call):
for(var i = 0; i < this.children[0].children.length; i++) { // <-- you are iterating over the children of root's left child
if(this.children[i].value) { // <-- but you are accessing root's current child
results.push(this.children[i].value);
}
}
is somewhat confusing. You are iterating over the children of root's left child children[0].children, but on each iteration you check if the root's children themselves children[i] have a value and you push that value.
This is incorrect and will break if, for example, the root only has a left child that has both children (i will be out of bounds).
Here's how you can approach this problem. The recursion to print the left tree in your case can be broken down into the following cases:
If the current node has no value, return an empty array
Else If the current node has no children, return an array only containing the current value
Else if the current node has a left child, run childrenArray on it recursively and add the results to the results array
Here's how that would look:
BinaryTree.prototype.childrenArray = function() {
var results = [];
// case 1:
if (this.value === undefined) {
return results;
}
// case 2:
results.push(this.value);
if (this.children.length === 0) {
return results;
}
// case 3:
var leftChild = this.children[0];
if (leftChild) {
results = results.concat(leftChild.childrenArray());
}
/* add code here for the right child to complete your function */
return results;
};
Full Example:
var BinaryTree = function(value) {
this.value = value;
this.children = [];
};
BinaryTree.prototype.addChild = function (value) {
if (value < this.value) {
if (this.children[0] === undefined) {
this.children[0] = new BinaryTree(value);
}
this.children[0].addChild(value);
} else if (value > this.value) {
if (this.children[1] === undefined) {
this.children[1] = new BinaryTree(value);
}
this.children[1].addChild(value);
}
};
BinaryTree.prototype.childrenArray = function() {
var results = [];
// case 1:
if (this.value === undefined) {
return results;
}
// case 2:
results.push(this.value);
if (this.children.length === 0) {
return results;
}
// case 3:
var leftChild = this.children[0];
if (leftChild) {
results = results.concat(leftChild.childrenArray());
}
/* add code here for the right child to complete your function */
return results;
};
var a = new BinaryTree(10);
a.addChild(4);
a.addChild(11);
a.addChild(3);
console.log(a.childrenArray()); // [10, 4, 3]
Last thing, based on your insertion logic (insert left if smaller, right if larger), you are building a Binary Search Tree not a Binary Tree. Binary tree's don't follow any particular insertion logic. Take a look at this question for clarification

Stripping html tags, 'RegExp-free-way'

I've got a bit paranoid lately about the solutions out there that deal with the task by using regular expressions to 'sanitize' html strings. They largely depend on how 'bullet-proof' given regex is. So, I came up with this snippet and hope to get some feedback about it from community. Thanks.
//
// #notags
String.prototype.notags = (function (doc) {
var mkel = doc.createElement.bind(doc);
var hasown = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
// #textlike-nodes
var textlike = {
12 : "NOTATION_NODE",
3 : "TEXT_NODE",
4 : "CDATA_SECTION_NODE",
5 : "ENTITY_REFERENCE_NODE",
6 : "ENTITY_NODE",
7 : "PROCESSING_INSTRUCTION_NODE",
8 : "COMMENT_NODE"
};
// #_notags
// main function
var _notags = function (tagedstring) {
var div;
var istxt = istextnode;
var nodes;
var nodetxt = getxt;
var res;
div = mkel('div');
div.innerHTML = (''+ tagedstring);
// get the div's descendants
// and read their text content
// until all of its childern are plain
// text nodes...
nodes = descendants(div);
while (!nodes.every(istxt)) {
div.innerHTML = nodetxt(div);
nodes = descendants(div);
}
res = div.innerHTML;
// get rid of temporary div
// prevents mem. leaks
div.innerHTML = '';
delete div;
return res;
};
// #save
// String#notags
return function () {
return _notags(this);
};
////////////////
////// #helpers
// #istextnode
function istextnode (node) {
return !(3 - node.nodeType);
}
// #descendants
function descendants (startnode, _nodels) {
_nodels || (_nodels = []);
var node = startnode.firstChild;
while (node) {
_nodels.push(node);
descendants(node, _nodels);
node = node.nextSibling;
}
return _nodels;
}
// #getxt
// loop each node's descendant
// and fetch it' text content
function getxt (node) {
var _ = {
str: '',
txt: textlike
};
descendants(node)
.forEach(getnodetext, _);
return _.str;
}
// #getnodetext
function getnodetext (node) {
//this: {str, txt}
if (hasown(this.txt, node.nodeType))
this.str += (node.data || node.textContent || node.nodeValue);
}
})(document);
// /eof

Trees Structure - Javascript - Parents?

Simply put
I have a tree structure made of objects.
Is it possible to build that tree and add to each object a reference to their parent ?
I know referencing works with objects, but i'm not sure if it would in that case?
I would like to be able to write something like this
currentLevel = this.getParent();
another exemple would be
this.getChildList().addChild({name: test,parent: this})
Without having copies and creating multiple tree from the first one.
2nd question
How would referencing works with array? Are they considered objects or does it depends on their content?
3nd question
Would saving the tree in the browser's cache, via string-JSON serialisation destroy the references?
You can do this be creating a "TreeNode" class:
var TreeNode = (function(){
//keep track of parent node
TreeNode.prototype.parent = null;
//keep track of children
TreeNode.prototype.children = [];
function TreeNode(parent) {
if(parent !== undefined) {
if(this.setParent(parent)) {
this.parent.addChild(this);
}
}
//...
}
TreeNode.prototype.setParent = function(parent) {
//add some sort of check to make sure it is a `TreeNode`
if(parent instanceof TreeNode) {
this.parent = parent;
return true;
}
return false;
}
TreeNode.prototype.addChild = function(child) {
//add some sort of check to make sure it is a `TreeNode`
if(child instanceof TreeNode) {
this.children.push(child);
child.setParent(this);
}
}
TreeNode.prototype.getParent = function(){
return this.parent;
}
TreeNode.prototype.getChildren = function(){
return this.children;
}
return TreeNode;
})();
And then you can expand from that.
Example Code:
var node_a = new TreeNode();
var node_b = new TreeNode(node_a);
var node_c = new TreeNode(node_a);
console.log(node_a.getParent(), node_c.get_parent()); //null , node_a
console.log(node_a.getChildren()); //[node_b, node_c]
This is just a start, it needs waaaaaaaaaay more expansion :-)
Okay, so there are most likely frameworks out there, but I wrote a quick thing which supports JSON serialisation and the reverse (via it's own methods). I took base inspiration from Neal's answer. Example
var a = new MyTreeNode('a'), // make some nodes
b = new MyTreeNode('b'),
c = new MyTreeNode('c');
a.addChild(b).addChild(c); // a parent of b parent of c
c.getParent() === b; // true
var str = a.toJSON(); // "{"nodeName":"a","childNodes":[{"nodeName":"b","childNodes":[{"nodeName":"c","childNodes":[]}]}]}"
MyTreeNode.parseJSON(str); // MyTreeNode (same structure as before)
Full code
/* MyTreeNode(String nodeName)
Instance Properties
- nodeName, String
- childNodes, Array of MyTreeNodes
- parentNode, MyTreeNode
Instance Methods
- addChild(MyTreeNode node), child MyTreeNode
- removeChild(MyTreeNode node), child MyTreeNode
- getParent, parent MyTreeNode
- getChildList, Array of MyTreeNodes
- serialise, JSON-safe Object
- toJSON, String
Constructor Methods
- deserialise(Object serialised), MyTreeNode
- parseJSON(String JSONString), MyTreeNode
*/
var MyTreeNode = (function () {
function MyTreeNode(nodeName) {
nodeName && (this.nodeName = nodeName);
this.childNodes = [];
}
MyTreeNode.prototype.parentNode = null;
MyTreeNode.prototype.childNodes = [];
MyTreeNode.prototype.nodeName = '';
// getters
MyTreeNode.prototype.getChildList = function () {
return this.childNodes = [];
};
MyTreeNode.prototype.getParent = function () {
return this.parentNode;
};
// add/remove
MyTreeNode.prototype.removeChild = function (node) {
var i = this.childNodes.indexOf(node);
if (node.parentNode !== this || i == -1)
throw new ReferenceError('node is not a child of this');
this.childNodes.splice(i, 1);
node.parentNode = null;
return node;
};
MyTreeNode.prototype.addChild = function (node) {
if (node.parentNode) node.parentNode.removeChild(node);
node.parentNode = this;
this.childNodes.push(node);
return node;
};
// JSON
MyTreeNode.prototype.serialise = function () {
var o = {
nodeName: this.nodeName,
childNodes: []
}, i;
for (i = 0; i < this.childNodes.length; ++i) {
o.childNodes.push(this.childNodes[i].serialise());
}
return o;
};
MyTreeNode.prototype.toJSON = function () {
return JSON.stringify(this.serialise());
};
MyTreeNode.deserialise = function (o) {
var p = new MyTreeNode(o.nodeName), i;
for (i = 0; i < o.childNodes.length; ++i) {
p.addChild(MyTreeNode.deserialise(o.childNodes[i]));
}
return p;
};
MyTreeNode.parseJSON = function (str) {
var o = JSON.parse(str);
return MyTreeNode.deserialise(o);
};
return MyTreeNode;
}());
You could traverse your object and add parent properties to every subobject:
function addParents(obj) {
var name;
for (name in obj) {
if (typeof obj[name] === "object") {
addParents(obj[name]);
obj[name].parent = obj;
}
}
}
var obj = {
g: {
k: [
{
r : 1
},
{
r : 1
}
],
j: {
h: 1
}
}
};
addParents(obj);
console.log(obj.g.parent === obj); //true
console.log(obj.g.k.parent === obj.g); //true
console.log(obj.g.k[1].parent === obj.g.k); //true
console.log(obj.g.j.parent === obj.g); //true
And if you want to add objects later on, you could use something like this:
function addChild(obj, child, name){
obj[name] = child;
child.parent = obj;
}
addChild(obj.g, {t:1}, "xy");
console.log(obj.g.xy.parent === obj.g); //true
FIDDLE

Categories