Binary Search Tree JavaScript implementation - remove function - javascript

Here's my implementation for a Binary Search Tree in JavaScript. All functions appear to be working properly except for the remove function. Specifically, it seems to be removing nodes properly until there's 2 nodes left in the tree:
var binaryTreeNode = function (value) {
return {
value : value,
left : null,
right : null
};
};
var binarySearchTree = function () {
var tree = Object.create( binarySearchTreeMethods );
tree.root = null;
return tree;
};
var binarySearchTreeMethods = {
insert: function (value, node) {
var newNode = binaryTreeNode( value );
// check if tree is empty
if ( this.isEmpty() ) {
this.root = newNode;
return;
}
// initialize node
if ( node === void 0 ) node = this.root;
// compare value with node.value
if ( value <= node.value ) {
// check if left exists
if ( node.left ) {
this.insert( value, node.left );
} else {
node.left = newNode;
}
} else {
if ( node.right ) {
this.insert( value, node.right );
} else {
node.right = newNode;
}
}
},
remove: function (value, node) {
var nextRightValue, nextLeftValue, minRight;
if ( !this.isEmpty() ) {
// initialize node
if ( node === void 0 ) node = this.root;
// compare the node's value with the value
if ( value < node.value ) {
// check if there is a left node
if ( node.left ) {
node.left = this.remove( value, node.left );
}
} else if ( value > node.value ) {
// check if there is a right node
if ( node.right ) {
node.right = this.remove( value, node.right );
}
} else {
// at this point, value === node.value
// check if node is a leaf node
if ( node.left === null && node.right === null ) {
// edge case of single node in tree (i.e. root node)
if ( this.getHeight() === 0 ) {
this.root = null;
return this.root;
} else {
node = null;
}
} else if ( node.left === null ) {
node = node.right;
} else if ( node.right === null ) {
node = node.left;
} else {
// node has both left and right
minRight = this.findMinValue( node.right );
node.value = minRight;
node.right = this.remove( minRight, node.right );
}
}
return node;
}
},
contains: function (value, node) {
if ( this.isEmpty() ) return false;
// tree is not empty - initialize node
if ( node === void 0 ) node = this.root;
// check if node's value is the value
if ( value === node.value ) return true;
if ( value < node.value ) {
// check if left node exists
return node.left ? this.contains( value, node.left ) : false;
} else {
// check if right node exists
return node.right ? this.contains( value, node.right ) : false;
}
},
findMaxValue: function (node) {
if ( !this.isEmpty() ) {
if ( node === void 0 ) node = this.root;
while ( node.right ) {
node = node.right;
}
return node.value;
}
},
findMinValue: function (node) {
if ( !this.isEmpty() ) {
if ( node === void 0 ) node = this.root;
while ( node.left ) {
node = node.left;
}
return node.value;
}
},
getHeight: function (node) {
if ( !this.isEmpty() ) {
// initialize node
if ( node === void 0 ) node = this.root;
// base case
if ( node.left === null && node.right === null ) return 0;
if ( node.left === null ) return 1 + this.getHeight( node.right );
if ( node.right === null ) return 1 + this.getHeight( node.left );
return 1 + Math.max( this.getHeight( node.left ), this.getHeight( node.right ) );
}
},
isEmpty: function () {
return this.root === null;
}
};
Inserting values into the binary search tree works fine:
var bst = binarySearchTree();
bst.insert(10);
bst.insert(5);
bst.insert(20);
bst.insert(30);
bst.insert(22);
bst.insert(18);
I come across an issue when I start removing the root value each time:
bst.remove(10); // this works fine and the resulting bst tree is structurally correct
bst.remove(18); // this works fine and the resulting bst tree is structurally correct
bst.remove(20); // this works fine and the resulting bst tree is structurally correct
bst.remove(22); // this works fine and the resulting bst tree is structurally correct
bst.remove(30); // THIS IS WHERE THE ISSUE OCCURS
Prior to removing 30, the tree only has two values: 30 as the root value and 5 as the root.left value. I would expect that removing 30 would give me a tree which has 5 as the root. However, removing 30 doesn't do anything to the tree; it remains the same.
Further testing shows that if I had removed 5 first and then 30, then everything works fine as well:
bst.remove(10); // this works fine and the resulting bst tree is structurally correct
bst.remove(18); // this works fine and the resulting bst tree is structurally correct
bst.remove(20); // this works fine and the resulting bst tree is structurally correct
bst.remove(22); // this works fine and the resulting bst tree is structurally correct
bst.remove(5); // Results in a tree with 30 as the root value
bst.remove(30); // Results in the empty tree where root === null
Can anyone help me understand why removing 30 initially didn't work?

Your code has a provision for the case when the found node is the root and it is the only node in the tree, and if a node has both a left and a right child, you overwrite its value. But when the node to remove is the root and it has only one child, there is nothing in your code that overwrites this.root, and you don't overwrite the root's value, so it is not removed and the tree remains unmodified.
You can fix this by changing this:
if ( node === void 0 ) node = this.root;
// compare the node's value with the value
if ( value < node.value ) {
to this:
if ( node === void 0 ) {
this.root = this.remove(value, this.root);
// compare the node's value with the value
} else if ( value < node.value ) {
Once that is fixed, you can simplify your logic a bit:
remove: function (value, node) {
if (!this.isEmpty()) {
// initialize node
if (!node) {
this.root = this.remove(value, this.root);
} else if (value < node.value && node.left) {
node.left = this.remove(value, node.left);
} else if (value > node.value && node.right) {
node.right = this.remove(value, node.right);
} else if (value === node.value) {
// check if node is a leaf node
if (node.left && node.right) {
// node has two children. change its value to the min
// right value and remove the min right node
node.value = this.findMinValue(node.right);
node.right = this.remove(node.value, node.right);
} else {
// replace the node with whichever child it has
node = node.left || node.right;
}
}
return node;
}
},
and then you can simplify it further by separating it into two methods:
remove: function (value) {
this.root = this._removeInner(value, this.root);
},
_removeInner: function (value, node) {
if (node) {
if (value < node.value) {
node.left = this._removeInner(value, node.left);
} else if (value > node.value) {
node.right = this._removeInner(value, node.right);
} else if (node.left && node.right) {
node.value = this.findMinValue(node.right);
node.right = this._removeInner(node.value, node.right);
} else {
node = node.left || node.right;
}
}
return node;
},
Demo
#wmock has asked how I went about solving this problem so I'll elaborate on that a bit.
The first thing I did was walk the code in the debugger, focusing on the bst.remove(30) part. I noticed that 30 was the root at that point and that it remained there after remove() was done. This led me to noticing that the code never modifies the root in that particular case.
I then looked at how the return value of this.remove() was being assigned to node.left and node.right, and with some recollection of BST algorithms, thought it would make sense to emulate that for the root as well. And that was indeed the answer.
There were a few things that motivated splitting the method into two methods:
I noticed that the method had a fair amount of special-case functionality that was only relevant for the initial call to bst.remove()
Checking this.isEmpty()
Using this.root for the value of node if node was null
Resetting this.root to null under certain cases when the tree height is 0
It seemed sloppy to be doing all of that in every pass through remove()
I also repeatedly found myself wanting to use if (!node) to check whether I had reached the edge of the tree, but I couldn't because there was that special case logic to use this.root when node was null.
Splitting the method into two parts resolved all of the above issues.
Note that in a lot of BST implementations, the functionality in _removeInner() would be a method on the binaryTreeNode type, and the tree would just interact with the root node. That eliminates the need to pass a node from one method call to the next:
In binarySearchTree:
remove: function (value) {
this.root && this.root.remove(value);
},
In binaryTreeNode:
remove: function (value) {
if (value < this.value) {
this.left = this.left && this.left.remove(value);
} else if (value > this.value) {
this.right = this.right && this.right.remove(value);
} else if (this.left && this.right) {
this.value = this.right.findMinValue();
this.right = this.right.remove(this.value);
} else {
return this.left || this.right;
}
return this;
},
findMinValue: function () {
return this.left ? this.left.findMinValue() : this.value;
}
Demo

Here is the full example of a Binary tree with insert and remove functionalities
function Node(val) {
this.data = val;
this.right = null;
this.left = null;
}
function BST() {
this.root = null;
this.insert = insert;
this.inOrder = inOrder;
this.remove = remove;
this.removeNode = removeNode;
this.kthSmallestNode = kthSmallestNode;
}
function insert(val) {
if (val == null || val == undefined)
return;
if (this.root == null) {
this.root = new Node(val);
return;
}
var current = this.root
var newNode = new Node(val);
while (true) {
if (val < current.data) {
if (current.left == null) {
current.left = newNode;
return;
}
current = current.left;
} else {
if (current.right == null) {
current.right = newNode;
return;
}
current = current.right;
}
}
}
function remove(val) {
this.root = removeNode(this.root, val);
}
function removeNode(current, value) {
if (value == null || value == undefined)
return;
if (value == current.data) {
if (current.left == null && current.right == null) {
return null;
} else if (current.left == null)
return current.right;
else if (current.right == null)
return current.left;
else {
var tempNode = kthSmallestNode(current.right);
current.data = tempNode.data;
current.right = removeNode(current.right, tempNode.data);
return current;
}
} else if (value < current.data) {
current.left = removeNode(current.left, value);
return current;
} else {
current.right = removeNode(current.right, value);
return current;
}
}
function kthSmallestNode(node) {
while (!(node.left == null))
node = node.left;
return node;
}
function inOrder(node) {
if (!(node == null)) {
inOrder(node.left);
console.log(node.data + " ");
inOrder(node.right);
}
}
var tree = new BST();
tree.insert(25);
tree.insert(20);
tree.insert(30);
tree.insert(27);
tree.insert(21);
tree.insert(16);
tree.insert(26);
tree.insert(35);
tree.remove(30)
console.log("Inorder : ")
console.log(tree.inOrder(tree.root))
Good Luck!!!

I have a pretty simplified answer that I think most people will understand and it takes into account children nodes. The key is that if you are removing a value with a right and left child that you first go left and then all the way right because this assures you that it will have no children and be easier to update.
removeNode(val) {
let currentNode, parentNode, nextBiggestParentNode=null, found=false, base=[this.root];
while(base.length > 0 && !found) {
currentNode = base.pop();
if(currentNode.value === val) {
found=true;
if(!currentNode.left && !currentNode.right) {
parentNode.right === currentNode ? parentNode.right = null : parentNode.left = null;
}
else if(!currentNode.right && currentNode.left) {
parentNode.right === currentNode ? parentNode.right = currentNode.left : parentNode.left = currentNode.left;
}
else if(!currentNode.left && currentNode.right) {
parentNode.right === currentNode ? parentNode.right = currentNode.right : parentNode.left = currentNode.right;
}
else {
let _traverse = node => {
if (node.right) {
nextBiggestParentNode = node;
_traverse(node.right);
}
else {
currentNode.value = node.value;
nextBiggestParentNode ? nextBiggestParentNode.right = null : currentNode.left = null;
}
}
_traverse(currentNode.left);
}
}
else {
parentNode = currentNode;
val > currentNode.value && currentNode.right ? base.unshift(currentNode.right) : base.unshift(currentNode.left);
}
}
return this;
}
that code is part of a class, here is the rest of my constructor code if anybody is interested
let TreeNode = class {
constructor(value, left=null, right=null) {
this.value = value;
this.left = left;
this.right = right;
}
}
let BST = class {
constructor(root=null) {
this.root = root;
}
insert(nodeToInsert) {
if (this.root === null) {
this.root = nodeToInsert;
} else {
this._insert(this.root, nodeToInsert);
}
}
_insert(root, nodeToInsert) {
if (nodeToInsert.value < root.value) {
if (!root.left) {
root.left = nodeToInsert;
} else {
this._insert(root.left, nodeToInsert);
}
} else {
if (!root.right) {
root.right = nodeToInsert;
} else {
this._insert(root.right, nodeToInsert);
}
}
}
here is some demo code to create a bst and remove a value
let bst = new BST();
const nums = [20,10,5,15,3,7,13,17,30,35,25,23,27,37,36,38];
function createBst() {
for (let i of nums) {
bst.insert(new TreeNode(i));
}
console.log(JSON.stringify(bst, null, 2));
bst.removeNode(35);
}
createBst();
console.log(JSON.stringify(bst, null, 2));

Related

Can you spot a mistake in this construction of a Binary Search Tree?

I am going through AlgoExpert and learning about Binary Search trees and their construction for the first time. The below implementation seems to be working locally for me as expected but I am getting errors for most test cases on AlgoExpert. This is my implementation:
class BST {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
insert(value) {
const searchTree = (node) => {
if (value < node.value) {
if (!node.left) {
node.left = new BST(value);
} else {
searchTree(node.left);
}
} else {
if (!node.right) {
node.right = new BST(value);
} else {
searchTree(node.right);
}
}
};
searchTree(this);
// Write your code here.
// Do not edit the return statement of this method.
return this;
}
contains(value) {
let currentNode = this;
while (currentNode) {
if (currentNode.value === value) {
return true;
}
if (value < currentNode.value) {
currentNode = currentNode.left;
} else {
currentNode = currentNode.right;
}
}
return false;
// Write your code here.
}
min() {
let currentNode = this;
while (currentNode.left) {
currentNode = currentNode.left;
}
return {
value: currentNode.value,
node: currentNode
};
}
remove(value) {
let nodeToBeRemoved = this;
while (nodeToBeRemoved.value !== value) {
if (value < nodeToBeRemoved.value) {
nodeToBeRemoved = nodeToBeRemoved.left;
} else {
nodeToBeRemoved = nodeToBeRemoved.right;
}
}
if (!nodeToBeRemoved.right) {
nodeToBeRemoved.value = null;
} else {
const {
value: minValue,
node
} = nodeToBeRemoved.right.min();
node.value = null;
nodeToBeRemoved.value = minValue;
}
// Write your code here.
// Do not edit the return statement of this method.
return this;
}
}
Can you see any mistake that could cause this error on Algo Expert? I don't see where the mistake is. This is the error I am getting:
Cannot read property 'toString' of null
TypeError: Cannot read property 'toString' of null
at constructBinaryTreeWithUniqueIds
at constructBinaryTreeWithUniqueIds
...
The remove method has some issues:
After the first while loop, nodeToBeRemoved could be null. In that case the next if statement will make an invalid reference with nodeToBeRemoved.right.
nodeToBeRemoved.value = null does not remove a node. It just modifies the value of a node to null. But it is still part of the tree, and could even have a left child.
The same is true for node.value = null. This remains part of the tree and could have a right child.
remove(value) {
let nodeToBeRemoved = this;
if (value < this.value) {
if (this.left) this.left = this.left.remove(value);
} else if (value > this.value) {
if (this.right) this.right = this.right.remove(value);
} else if (!this.right) {
return this.left;
} else if (!this.left) {
return this.right;
} else {
const minValue = this.right.min().value;
this.right.remove(minValue); // use recursion to delete that min-node
this.value = minValue;
}
return this;
}

How to use recursion function to traverse tree in Javascript

I was building a tree traverse function and it has to use recursion.
What I want the output to be is
'{"value":9,"left":{"value":4,"left":{"value":1},"right":{"value":6}},"right":{"value":20,"left":{"value":15},"right":{"value":170}}}'
Could someone figure out how to use recursion in the traverse function to get the output?
Here is my JS:
class Node {
constructor(value){
this.left = null;
this.right = null;
this.value = value;
}
}
class BinarySearchTree {
constructor(){
this.root = null;
}
insert(value){
const newNode = new Node(value);
if (this.root === null) {
this.root = newNode;
} else {
let currentNode = this.root;
while(true){
if(value < currentNode.value){
//Left
if(!currentNode.left){
currentNode.left = newNode;
return this;
}
currentNode = currentNode.left;
} else {
//Right
if(!currentNode.right){
currentNode.right = newNode;
return this;
}
currentNode = currentNode.right;
}
}
}
}
}
const tree = new BinarySearchTree();
tree.insert(9)
tree.insert(4)
tree.insert(6)
tree.insert(20)
tree.insert(170)
tree.insert(15)
tree.insert(1)
JSON.stringify(traverse(tree.root))
// 9
// 4 20
//1 6 15 170
function traverse(node) {
const tree = { value: node.value };
tree.left=node.left
if(node.left===null) {
return null
}else{
traverse(node.left);
}
tree.right=node.right
if(node.right===null) {
return null
}else{
traverse(node.right);
}
}
You're on the right track; I see that you need specially-formatted objects in your result string. I recommend starting by checking whether the current node is null; if so, return nothing (this key will be ignored by the calling function). Otherwise, create a node object to prepare for return and traverse left and right children. After traversing both subtrees recursively, return the root node. This will build the result structure up from the leaves and end with the root.
In your code,
if(node.left===null) {
return null
is a bit premature, for example. If node has a right subtree, we don't want to abandon traversing it. It's also necessary to return something to the caller in all cases except for empty children.
Also, you may consider putting traverse in the BinaryTree class and have it operate on its member field; I left it as-is in the below example.
Lastly, this is a pre-order traversal; visit the root first, then the left and right subtrees.
function traverse(node) {
if (node) {
const left = traverse(node.left);
const right = traverse(node.right);
return {
value: node.value,
[left&&"left"]: left,
[right&&"right"]: right
};
}
}
class Node {
constructor(value, left=null, right=null) {
this.value = value;
this.left = left;
this.right = right;
}
}
class BinarySearchTree {
constructor() {
this.root = null;
}
insert(value) {
const newNode = new Node(value);
if (this.root === null) {
this.root = newNode;
}
else {
let currentNode = this.root;
while (true) {
if (value < currentNode.value) {
if (!currentNode.left) {
currentNode.left = newNode;
return this;
}
currentNode = currentNode.left;
}
else {
if (!currentNode.right) {
currentNode.right = newNode;
return this;
}
currentNode = currentNode.right;
}
}
}
}
}
const tree = new BinarySearchTree();
tree.insert(9);
tree.insert(4);
tree.insert(6);
tree.insert(20);
tree.insert(170);
tree.insert(15);
tree.insert(1);
console.log(JSON.stringify(traverse(tree.root)));
console.log(traverse(tree.root));
// 9
// 4 20
// 1 6 15 170

BinarySearchTree's insert function in javascript

I was building a BinarySearchTree by using javascript
but the insert function in my code deoesn't run what i want
my ideal result is
{"value":9,"left":{"value":4,"left":{"value":1,"left":null,"right":null},"right":{"value":6,"left":null,"right":null}},"right":{"value":20,"left":{"value":15,"left":null,"right":null},"right":{"value":170,"left":null,"right":null}}}
but my result is
'{"value":9,"left":null,"right":{"left":null,"right":{"left":null,"right":{"left":null,"right":{"left":null,"right":{"left":null,"right":{"left":null,"right":null}}}}}}}'
I think the problem is in my insert function
Here is my JS:
class Node {
constructor(value){
this.left = null;
this.right = null;
this.value = value;
}
}
class BinarySearchTree {
constructor(){
this.root = null;
}
insert(value){
var root=this.root
if(!root){
this.root=new Node(value)
}else{
var currentNode=root;
var newNode=new Node(value)
while(currentNode){
if(value<currentNode.value){
if(!currentNode.left){
currentNode.left=new Node;
break;
}
else{
currentNode=currentNode.left;
}
}else{
if(!currentNode.right){
currentNode.right=new Node;
break;
}else{
currentNode=currentNode.right
}
}
}
}
}
lookup(value){
var root=this.root
var searchNode = new Node(value)
if(!this.root){
return null;
}
if(searchNode===root){
return root
}else{
if(searchNode.value>root){
return root.right.value
}else{
return root.left.value
}
}
}
}
const tree = new BinarySearchTree();
tree.insert(9)
tree.insert(4)
tree.insert(6)
tree.insert(20)
tree.insert(170)
tree.insert(15)
tree.insert(1)
JSON.stringify(traverse(tree.root))
// 9
// 4 20
//1 6 15 170
function traverse(node) {
const tree = { value: node.value };
tree.left = node.left === null ? null : traverse(node.left);
tree.right = node.right === null ? null : traverse(node.right);
return tree;
}
Your Node class was instantiated as newNode so change all new Node into newNode *except for the first instance of new Node of course.
var newNode=new Node(value) // Leave this one alone and fix the rest
var searchNode = new Node(value) // Leave this one alone as well
var insertNode = function(node, newNode) {
if (newNode.key < node.key) {
if (node.left === null) {
node.left = newNode;
} else {
insertNode(node.left, newNode);
}
} else {
if (node.right === null) {
node.right = newNode;
} else {
insertNode(node.right, newNode);
}
}
};

binary tree add an undefined node

Problem
I'm trying to study better the tree theory, i can add one or more node without problems but i noticed that if i tried to launch multiple add function without pass a parameter, simply it doesn't work. Could you explain where is my mistake ?
Code
BinarySearchTree.prototype.makeNode = function(value) {
var node = {};
node.value = value;
node.left = null;
node.right = null;
return node;
};
BinarySearchTree.prototype.add = function(value) {
var currentNode = this.makeNode(value);
if (!this.root) {
this.root = currentNode;
} else {
this.insert(currentNode);
}
return this;
};
BinarySearchTree.prototype.insert = function(currentNode) {
var value = currentNode.value;
var traverse = function(node) {
if (value > node.value) {
if (!node.right) {
node.right = currentNode;
return;
} else traverse(node.right);
} else if (value < node.value) {
if (!node.left) {
node.left = currentNode;
return;
} else traverse(node.left);
}
};
traverse(this.root);
};
Now if i try to
var bst = new BinarySearchTree();
bst.add(3).add(2);
console.log(bst);
i will have this console.log
if i try to pass an undefined value
var bst = new BinarySearchTree();
bst.add().add(2);
console.log(bst);
Expectation
I expect that the last console.log doesn't lost the value of 2.
. i read this post to understand better what if i didn't pass any value to a function
What happens if I don't pass a parameter in a Javascript function?
and other posts ( like medium and stack overflow ) and guide related to the tree theory but i didn't find any solution
SOLUTION
Thanks to the recommendation and the correction of #Nina Scholz i just added this lines to this function
BinarySearchTree.prototype.add = function(value) {
if (typeof value == 'undefined') {
value = null;
}
var currentNode = this.makeNode(value);
if (!this.root) {
this.root = currentNode;
console.log('sei qui')
} else {
this.insert(currentNode);
}
return this;
};
Nothing happens, because both conditions evaluate with undefined as value to false.
if (value > node.value) {
// ...
} else if (value < node.value) {
// ...
}
function BinarySearchTree() {}
BinarySearchTree.prototype.makeNode = function(value) {
var node = {};
node.value = value;
node.left = null;
node.right = null;
return node;
};
BinarySearchTree.prototype.add = function(value) {
var currentNode = this.makeNode(value);
if (!this.root) {
this.root = currentNode;
} else {
this.insert(currentNode);
}
return this;
};
BinarySearchTree.prototype.insert = function(currentNode) {
var value = currentNode.value;
var traverse = function(node) {
if (value > node.value) {
if (!node.right) {
node.right = currentNode;
return;
} else traverse(node.right);
} else if (value < node.value) {
if (!node.left) {
node.left = currentNode;
return;
} else traverse(node.left);
}
};
traverse(this.root);
};
var bst = new BinarySearchTree();
bst.add(3).add(2).add();
console.log(bst);

Writing a recursive add method for a Javascript Binary Search Tree

I'm trying to write an add/insert method for a BST in JS, but can't seem to get it working for some reason. My code is here:
function Node(value) {
this.value = value;
this.left = null;
this.right = null;
}
function BinarySearchTree() {
this.root = null;
this.add = function(insertElem){
let currNode = this.root;
var recurInsert = function(elem, node){
if(node == null){
let newNode = new Node(elem);
node = newNode;
console.log("firstNode");
return undefined;
}
else if(elem == node.value){
console.log("equal val");
return null
}
else if(elem > node.value){
console.log("go right");
recurInsert(elem, node.right);
}
else{
console.log("go left");
recurInsert(elem, node.left);
}
}
recurInsert(insertElem, currNode);
}
}
Specifically, the line node = newNode doesn't actually set node to newNode. I suspect that this could have something to do with pass-by-value nature of JavaScript, but I'm not completely sure.
Where did I go wrong?
Also, I'm hoping to keep this recursive form for now if possible.
Basically you need to hand over the object reference to the recursive function, because if not, you create new nodes without linking to the root node.
This code takes an object and the direction as key and checkes the four different dicision to make. If a new node has to be assigned, the object and the key is used.
If a value is smaller or greater than the node's value, the node is used along with the new direction for checking.
function Node(value) {
this.value = value;
this.left = null;
this.right = null;
}
function BinarySearchTree() {
this.root = null;
this.add = function (value) {
function check(node, direction) {
if (node[direction] === null) {
node[direction] = new Node(value);
console.log('new node', value);
return;
}
if (node[direction].value === value) {
console.log('equal value', value);
return;
}
if (node[direction].value > value) {
console.log('go left', node[direction].value);
check(node[direction], 'left');
return;
}
if (node[direction].value < value) {
console.log('go right', node[direction].value);
check(node[direction], 'right');
}
}
check(this, 'root');
};
}
var tree = new BinarySearchTree;
tree.add(10);
tree.add(5);
tree.add(15);
tree.add(2);
tree.add(4);
tree.add(11);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
An even shorter approach by using a default node.
function Node(value) {
this.value = value;
this.left = null;
this.right = null;
}
function BinarySearchTree() {
this.root = null;
this.add = function (value) {
function check(node) {
if (node.value === value) {
return;
}
if (node.value > value) {
check(node.left = node.left || new Node(value));
return;
}
if (node.value < value) {
check(node.right = node.right || new Node(value));
}
}
check(this.root = this.root || new Node(value));
};
}
var tree = new BinarySearchTree;
tree.add(10);
tree.add(5);
tree.add(15);
tree.add(2);
tree.add(4);
tree.add(11);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Small example of changing objects vs properties
function assign(o) { // take object reference as value of o
o = { bar: 43 }; // assign a new value to o, object keeps it value
console.log('o', o); // the reference to object is replaced by an own object
}
function change(o) { // take object reference as value of o
o.bar = 41; // take object reference and assign a new property
console.log('o', o); // because of the object reference, o and object has changed
}
var object = { foo: 42 };
console.log('object', object);
assign(object);
console.log('object', object);
change(object);
console.log('object', object);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The problem is that you need to set the node.right or node.left to the newNode and not node = newNode. Otherwise there is no linking of references and your root will never have any children.
So your insertions should actually be done here, if right.next or left.next is null, rather than on the next recursion.
else if(elem > node.value){
console.log("go right");
if (node.right == null)
node.right = new Node(elem);
else
recurInsert(elem, node.right);
}
else{
console.log("go left");
if (node.left == null)
node.left = new Node(elem);
else
recurInsert(elem, node.left);
}
You can also remove the whole if (node == null) { ... } section, and simply check if the root is null once before starting
if (root == null) {
root = new Node(insertElem);
return null;
}
Here is the full code:
function Node(value) {
this.value = value;
this.right = null;
this.left = null;
}
function BinarySearchTree() {
this.root = null;
this.add = function(value) {
if (this.root == null) {
this.root = new Node(value);
return;
}
var recInsert = function(value, node) {
if (value == node.value) {
print("equal");
return;
}
if (value < node.value) {
if (node.left == null)
node.left = new Node(value);
else
recInsert(value, node.left);
}
else {
if (node.right == null)
node.right = new Node(value);
else
recInsert(value, node.right);
}
}
recInsert(value, this.root);
}
this.print = function() {
if (this.root != null) {
var rec = function(node) {
if (node == null)
return;
rec(node.left);
print(node.value);
rec(node.right);
}
rec(this.root);
}
}
}

Categories