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");
}
}
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;
}
class Node{
constructor(element){
this.element = element;
this.right = null;
this.left = null;
}
}
class BST{
constructor(){
this.head = null;
}
add(element){
var node = new Node(element);
if(this.head === null){
this.head = node;
}else{
this.insertNode(this.head,node);
}
}
insertNode(node,key){
if(key.element < node.element){
if(node.left === null){
node.left = key;
}else{
this.insertNode(node.left,key);
}
}else{
if(node.right === null){
node.right = key;
}else{
this.insertNode(node.right, key);
}
}
}
remove(element){
this.head = this.removeNode(this.head,element);
}
removeNode(node,key){
if(node === null){
return null;
}else if(key < node.element){
node.left = this.removeNode(node.left,key);
return node;
}else if(key > node.element){
node.right = this.removeNode(node.right,key);
return node;
}else{
if(node.left === null && node.right === null){
node = null;
return node;
}
if(node.left === null){
node = node.right;
return node;
}else if(node.right === null){
node = node.left;
return node;
}
var temp = this.findMinNode(node.right);
node.element = temp.element;
node.right = this.removeNode(node.right, temp.element);
return node;
}
}
findMinNode(node){
if(node.left === null){
return node;
}else{
this.findMinNode(node.left);
}
}
}
var bst = new BST();
bst.add(10);
bst.add(5);
bst.add(3);
bst.add(7);
bst.add(4);
bst.add(2);
bst.add(6);
bst.add(9);
bst.add(8);
bst.add(15);
bst.add(24);
bst.add(22);
bst.add(25);
bst.add(21);
bst.remove(3);
console.log(bst);
When I removing node '5' from the binary tree, it show error that 'Cannot read property 'element' of undefined' but when i deleting the node '3' from the binary tree the it not showing me error, on that time the code works properly and deleting the node '3' perfectly.
enter code here
class Node{
constructor(element){
this.element = element;
this.right = null;
this.left = null;
}
}
class BST{
constructor(){
this.head = null;
}
add(element){
var node = new Node(element);
if(this.head === null){
this.head = node;
}else{
this.insertNode(this.head,node);
}
}
insertNode(node,key){
if(key.element < node.element){
if(node.left === null){
node.left = key;
}else{
this.insertNode(node.left,key);
}
}else{
if(node.right === null){
node.right = key;
}else{
this.insertNode(node.right, key);
}
}
}
remove(element){
this.head = this.removeNode(this.head,element);
}
removeNode(node,key){
if(node === null){
return null;
}else if(key < node.element){
node.left = this.removeNode(node.left,key);
return node;
}else if(key > node.element){
node.right = this.removeNode(node.right,key);
return node;
}else{
if(node.left === null && node.right === null){
node = null;
return node;
}
if(node.left === null){
node = node.right;
return node;
}else if(node.right === null){
node = node.left;
return node;
}
var temp = this.findMinNode(node.right);
node.element = temp.element;
node.right = this.removeNode(node.right, temp.element);
return node;
}
}
findMinNode(node){
if(node.left === null){
return node;
}else{
this.findMinNode(node.left);
}
}
}
var bst = new BST();
bst.add(10);
bst.add(5);
bst.add(3);
bst.add(7);
bst.add(4);
bst.add(2);
bst.add(6);
bst.add(9);
bst.add(8);
bst.add(15);
bst.add(24);
bst.add(22);
bst.add(25);
bst.add(21);
bst.remove(5);
console.log(bst);
output: for removing node 5 from the binary tree
node.element = temp.element;
^
TypeError: Cannot read property 'element' of undefined
output: for removing node 3 from the binary tree.
BST {
head: Node {
element: 10,
right: Node { element: 15, right: [Node], left: null },
left: Node { element: 5, right: [Node], left: [Node] }
}
}
The problem is in findMinNode method. You probably forgot to add return inside the else statement:
findMinNode(node) {
if (node.left === null) {
return node;
} else {
// return the value of recursive call
return this.findMinNode(node.left);
}
}
In the last method dfs(), after the node will be '1' the two if statement will not go into and it will go until the return statement without any line that call the method again, !!!but it call it self again!!!
who does that come?
I'm using JS.
Here is the code with online compiler: https://repl.it/repls/EnchantingSpanishBlockchain
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;
}
}
}
}
}
function dfs(node, list) {
if (node.left) {
dfs(node.left, list);
}
if (node.right) {
dfs(node.right, list);
}
list.push(node.value);
return list;
}
// 9
// 4 20
//1 6 15 170
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)
//DFTPostOrder
console.log(dfs(tree.root, []));
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);