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);
}
}
Related
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);
}
}
};
I'm creating a Binary Search Tree class, and getting confused as to how the while loop works.
if (value === currentNode.value) return;
if the same value entered is already in there return false, but this is also the base case?
if I take it out, the code breaks. how does it break the loop when I'm not entered an existing value?
class Node {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor() {
this.root = null;
}
insert(value) {
const newNode = new Node(value);
if (this.root === null) this.root = newNode;
let currentNode = this.root;
while (currentNode !== null) {
if (value === currentNode.value) return;
if (value < currentNode.value) {
if (currentNode.left === null) currentNode.left = newNode;
currentNode = currentNode.left;
} else {
if (currentNode.right === null) currentNode.right = newNode;
currentNode = currentNode.right;
}
}
}
}
Your loop break because you if condition only check for values less than or greater than and equal. You need a to insert if (value === currentNode.value) return;
inside else condition. Basically, inside else you need to check if the value is equal or greater than. Right now you don't check it.
insert(value) {
const newNode = new Node(value);
if (this.root === null) this.root = newNode;
let currentNode = this.root;
while (currentNode !== null) {
if (value < currentNode.value) {
if (currentNode.left === null) currentNode.left = newNode;
currentNode = currentNode.left;
} else {
if (value === currentNode.value) return false;
if (currentNode.right === null) currentNode.right = newNode;
currentNode = currentNode.right;
}
}
}
here is another insert methods you can try
class Node {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor() {
this.root = null;
}
insert(value){
let newNode = new Node(value);
if(this.rootNode == null){
this.rootNode = newNode;
return this;
}else{
let currentNode = this.rootNode;
while(true){
if(value > currentNode.value){
if(currentNode.right == null){
currentNode.right = newNode;
return this;
}
currentNode = currentNode.right;
}else if(value < currentNode.value){
if(currentNode.left == null){
currentNode.left = newNode;
return this;
}
currentNode = currentNode.left;
}
}
}
}
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);
}
}
}