recursion on bst in JavaScript - javascript

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;
}
}
}
}

Related

Is this pop() method for linked list in JavaScript correct? It works but I'm curious that if I use the correct method or not

pop(){
if(this.head == null){
return undefined;
}
else if(this.head == this.tail){
this.head = null;
this.tail = null;
this.length--
}
else{
let temp = this.head;
let pre = this.head;
while(temp.next){
pre = temp;
temp = temp.next;
}
this.tail = pre;
this.tail.next = null;
this.length--
}
I'm more concerned about the condition in which there's only one item inside the linked list.
The code is fine.
Here is a program that will test the implementation. Of course, the class needs to be completed with some other methods. The return undefined can be simplified to just return.
class Node {
constructor(value, next=null) {
this.value = value;
this.next = next;
}
}
class LinkedList {
constructor(...values) {
this.head = this.tail = null;
this.length = 0;
for (value of values) {
this.push(value);
}
}
push(value) {
if (this.tail) {
this.tail = this.tail.next = new Node(value);
} else {
this.head = this.tail = new Node(value);
}
this.length++;
}
pop(){
if (this.head == null){
return;
}
else if (this.head == this.tail){
this.head = null;
this.tail = null;
this.length--
}
else {
let temp = this.head;
let pre = this.head;
while(temp.next){
pre = temp;
temp = temp.next;
}
this.tail = pre;
this.tail.next = null;
this.length--
}
}
*[Symbol.iterator]() {
for (let node = this.head; node; node = node.next) {
yield node.value;
}
}
consistent() {
if (this.length != [...this].length) throw "length is inconsistent";
if (this?.tail?.next) throw "tail is inconsistent";
}
}
// Perform tests by doing the same operations on a native array simultaneously and comparing the result
let list = new LinkedList;
let arr = [];
for (let i = 0; i < 10000; i++) {
let choice = Math.random() > 0.5 && list.length < 10;
let value = Math.floor(Math.random() * 100);
if (choice) {
list.push(value);
arr.push(value);
} else {
list.pop();
arr.pop();
}
list.consistent();
if (JSON.stringify(arr) !== JSON.stringify([...list])) throw "Difference detected";
}
console.log("Tests done: all OK");
In JavaScript it is customary for pop() to return the value that was popped (this is not the case in every language, e.g. C++), as this is how the native array prototype defines pop. So you might want to consider to apply the same principle on your pop method.
Here is a version of the above code that includes that feature (and tests it):
class Node {
constructor(value, next=null) {
this.value = value;
this.next = next;
}
}
class LinkedList {
constructor(...values) {
this.head = this.tail = null;
this.length = 0;
for (value of values) {
this.push(value);
}
}
push(value) {
if (this.tail) {
this.tail = this.tail.next = new Node(value);
} else {
this.head = this.tail = new Node(value);
}
this.length++;
}
pop() {
if (this.head == null){
return;
}
const value = this.tail.value;
if (this.head == this.tail){
this.head = null;
this.tail = null;
} else {
let temp = this.head;
let pre = this.head;
while(temp.next){
pre = temp;
temp = temp.next;
}
this.tail = pre;
this.tail.next = null;
}
this.length--;
return value;
}
*[Symbol.iterator]() {
for (let node = this.head; node; node = node.next) {
yield node.value;
}
}
consistent() {
if (this.length != [...this].length) throw "length is inconsistent";
if (this?.tail?.next) throw "tail is inconsistent";
}
}
let list = new LinkedList;
let arr = [];
for (let i = 0; i < 10000; i++) {
let choice = Math.random() > 0.5 && list.length < 10;
let value = Math.floor(Math.random() * 100);
if (choice) {
list.push(value);
arr.push(value);
} else {
if (list.pop() !== arr.pop()) throw "Inconsistent pop return value";
}
list.consistent();
if (JSON.stringify(arr) !== JSON.stringify([...list])) throw "JSON is different";
}
console.log("tests done");
In the case when there is only one item in the list, this might not work.
This piece of code will not run:
while(temp.next){
pre = temp;
temp = temp.next;
}
The length will be reduced. But i guess you will have to point both this.head and this.tail to null, in the case length is 1.

Facing problem when removing node from the binary tree?

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);
}
}

who does the method call it self again after the return?

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, []));

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);
}
}
};

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