This is a Binary Tree I've made.
The problem: When i am deleting a data, it doesn't stop running when going from Left to Right, so it only goes in one direction. it deletes properly when it deletes all Left only and also, all Right only.
This runs properly:
BST.insert(10);
BST.insert(9);
BST.insert(8);
BST.insert(7);
BST.insert(6);
BST.insert(5);
BST.insert(4);
BST.Delete(4);
or
BST.insert(10);
BST.insert(11);
BST.insert(12);
BST.insert(13);
BST.insert(14);
BST.Delete(14);
but if you run this it stays in the loop like all conditions inside are false
BST.insert(10)
BST.insert(5)
BST.insert(8)
BST.insert(7)
BST.insert(6)
BST.insert(5)
BST.Delete(6)
You can try it yourself:
var BST = (function(){
// PRIVATE
var root = null;
// NODE OBJECT
var Node = function (data, left, right) {
this.data = data;
this.left = left;
this.right = right;
}
// PUBLIC
return {
insert: function(data) {
const node = new Node(data,null, null);
if (root === null) {
root = node;
} else {
let current = root;
while (true) {
if (current.data > data) {
if (current.left === null) {
current.left = node;
console.log(root+ " 1");
break;
}
current = current.left;
} else {
if (current.right === null) {
current.right = node;
console.log(root+ " 2");
break;
}
current = current.right;
}
}
}
},
Delete: function(data) {
if (root === null) {
return console.log("Nothings in Tree");
} else if (root.data === data ) {
root = null;
return console.log("found values");
}
// condition
let current = root;
while (true) {
//CHECK If a value exist to the left or right
if (current.data > data) {
if (current.left === null) {
return console.log("Could not find value");
}
} else if (current.data < data) {
if (current.right === null) {
return console.log("Could not find value");
}
}
// if left exist
if(current.left !== null){
if (current.left.data === data) { // if found data
console.log(`${data} has been remove from the node`);
current.left = null;
break;
} else if (current.left.data > data) {
//MOVE to the left==============
console.log(current.left.data+ " .Great");
current = current.left;// moves to the left
}
}
if (current.right !== null) {
if (current.right.data === data) {
console.log(`${data} has been remove from the node`);
current.right = null;
break;
} else if (current.right.data < data) {
//MOVE to the right==============
console.log(current.right.data +".Less");
current = current.right;
}
}
}
},
show: function() {
console.log(root);
},
test: function() {
console.log("test is working");
}
}
})();
It appears that i have over look a condition.
// if left exist
if(current.left !== null){
if (current.left.data === data) { // if found data
console.log(`${data} has been remove from the node`);
current.left = null;
break;
} else if (current.left.data > data) {
//MOVE to the left==============
console.log(current.left.data+ " .Great");
current = current.left;// moves to the left
}
}
The "else if (current.left.data > data)" should be replace with just "else" same with the right side. The answer is below.
var BST = (function(){
// PRIVATE
var root = null;
// NODE OBJECT
var Node = function (data,left,right){
this.data = data;
this.left = left;
this.right = right;
}
/*function currentToNull(current, data){
if(current === null){ // repeated operation
current = data;
}
}*/
// PUBLIC
return {
insert: function(data){
const node = new Node(data,null, null);
if(root === null){
root = node;
}else{
let current = root;
while(true){
if(current.data > data){
if(current.left === null){
current.left = node;
console.log(root+ " 1");
break;
}
current = current.left;
}else{
if(current.right === null){
current.right = node;
console.log(root+ " 2");
break;
}
current = current.right;
}
}
}
},
Delete: function(data){
if(root === null){
return console.log("Nothings in Tree");
}
// condition
let current = root, right_leaf, left_leaf;
while(true){
right_leaf = current.right; // keep track of left
left_leaf =current.left; // keep track of right
//CHECK If a value exist to the left or right
if(current.data > data){
if(left_leaf === null){
return console.log("Could not find value");
}
}else if(current.data < data){
if(right_leaf === null){
return console.log("Could not find value");
}
} else if(current.data === data){
current = null;
return console.log("data found");
}
if(left_leaf !== null){// L Leaf Data exist
if(left_leaf.data === data){ // if found data
console.log(`${data} has been remove from the node`);
current.left = null;
break;
}else if(left_leaf.data > data){ //MOVE to the left======================
console.log(" Move Left of left");
current = current.left;// moves to the left
} else if(left_leaf.data < data ){
console.log(" Move Right of left");
current = left_leaf;
}
}
if (right_leaf !== null){
if(right_leaf.data === data){
console.log(`${data} has been remove from the node`);
right_leaf = null;
break;
}else if(right_leaf.data < data){ //MOVE to the right=======================
console.log(" Move Right of right");
current = right_leaf;
} else if(right_leaf.data > data ){
console.log(" Move Left of right");
current = right_leaf;
}
}
}
}
,
show: function(){
console.log(root);
},
test: function (){
console.log("test is working");
}
}
})();
//show();
Related
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;
}
I am trying to make a Binary Search Tree (BST) class in JavaScript.
In JS objects are passed/assigned by reference but it looks like that this has some issue in the remove method. The remove method is not removing the node which I want it to remove.
class Node {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BST {
constructor() {
this.root = null;
}
add(value){
if(!this.root){
this.root = new Node(value);
return this;
}
addNode(this.root);
return this;
function addNode(node) {
if(value < node.value){
if(!node.left){
node.left = new Node(value);
}else{
addNode(node.left);
}
}
if(node.value < value){
if(!node.right){
node.right = new Node(value);
}else{
addNode(node.right);
}
}
}
}
find(value){
if(!this.root){
return;
}
return findNode(this.root);
function findNode(node) {
if(node.value === value){
return node;
}
if(value < node.value){
if(!node.left){
return;
}else{
return findNode(node.left);
}
}else{
if(!node.right){
return;
}else{
return findNode(node.right);
}
}
}
}
remove(value){
if(!this.root){
return this;
}
return removeNode(this.root);
function removeNode(node) {
if(node.value === value){
return actualRemoval(node);
}
if(value < node.value){
if(!node.left){
return;
}else{
return removeNode(node.left);
}
}else{
if(!node.right){
return;
}else{
return removeNode(node.right);
}
}
}
function actualRemoval(node) {
let tmp = Object.assign(node);
if(!node.left && !node.right){
node = null;
return tmp;
}
if(!node.left){
node = node.right;
return tmp;
}
if(!node.right){
node = node.left;
return tmp;
}
//if the node has both the children.
node.value = popMin(node.right).value;
return tmp;
}
function popMin(node) {
if(!node.left){
let tmp = Object.assign(node);
node = node.right;
return tmp;
}
return popMin(node.left);
}
} //end of function remove()
} //end of class BST
let myBST = new BST();
myBST.add(5).add(6).add(3).add(4).add(7).add(5.5)
// console.log(myBST.add(5).add(6).add(3).add(4).add(7).add(5.5));
// console.log(myBST.find(6));
console.log(myBST.remove(3));
console.log(myBST);
In the second to last line I am trying to remove a node with value 3.
But the last line displays a tree with node 3 present in it.
remove(value){
if(!this.root){
return this;
}
return removeNode(this.root, null);//second argument is the
function removeNode(node, parent, leftOrRight) {
if(node.value === value){
return actualRemoval(node, parent, leftOrRight);
}
if(value < node.value){
if(!node.left){
return;
}else{
return removeNode(node.left, node, "l");
}
}else{
if(!node.right){
return;
}else{
return removeNode(node.right, node, "r");
}
}
}
function actualRemoval(node, parent, leftOrRight) {
let tmp = Object.assign(node);
if(!node.left && !node.right){
if(parent){
if(leftOrRight === "l"){
parent.left = null;
}else{
parent.right = null;
}
}else{
node = null;
}
return tmp;
}
if(!node.left){
if(parent){
if(leftOrRight === "l"){
parent.left = node.right;
}else{
parent.right = node.right;
}
}else{
node = node.right; //this case runs once node is root
}
return tmp;
}
if(!node.right){
if(parent){
if(leftOrRight === "l"){
parent.left = node.leftt;
}else{
parent.right = node.left;
}
}else{
node = node.left; //this case runs once node is root
}
return tmp;
}
//if the node has both the children.
node.value = popMin(node.right, node, "r").value;//it is always called for right side with popMin
return tmp;
}
function popMin(node, parent, leftOrRight) {
if(!node.left){
let tmp = Object.assign(node);
if(leftOrRight == "l"){
parent.left = node.right;
}else{
parent.right = node.right;
}
return tmp;
}
return popMin(node.left, node, "l");
}
}
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);
}
}
};
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);
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);
}
}
}