How to make binary tree from array in javascript? - javascript

I have an array var array = [8,10,12,5,3,6];
Logic
First node would be root node.
If new node value is less or equal =< than parent node, It would be left node of parent node
If new node value is greater > than parent node, It would be right node of parent node
And I am trying to achieve output like below object:
{
value:8,
left:{
value:5,
left:{ value:3 },
right:{value:6}
},
right:{
value:10,
right:{value:12}
}
}
Which would be in image like this
I tried below code:
var arr = [8,10,12,5,3,6];
var root = arr[0];
var rv = {};
for (var i = 0; i < arr.length; i++){
if(arr[i] < root){
rv.left = arr[i];
}else{
rv.right = arr[i];
}
}
console.log(rv);
Please help me to solve this.

You could use a Node instance for new nodes and a function for inserting nodes.
Then iterate the values and build a new tree.
function Node(value) {
this.value = value;
// this.left = null;
// this.right = null;
}
function insertNode(tree, value) {
var node = tree,
key;
while (node.value !== value) {
key = value < node.value ? 'left' : 'right';
if (!node[key]) {
node[key] = new Node(value);
break;
}
node = node[key];
}
return tree;
}
var array = [8, 10, 12, 5, 3, 6],
tree = array.reduce((t, v) => t ? insertNode(t, v) : new Node(v), null);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

While it is close to Nina's answer i believe to be a little more concise;
var data = [8,10,12,5,3,6],
tree;
function insertBinTree (t = {value: void 0, left: void 0, right: void 0}, n){
t.value !== void 0 ? t.value > n ? t.left = insertBinTree(t.left,n)
: t.right = insertBinTree(t.right,n)
: t.value = n;
return t;
}
tree = data.reduce(insertBinTree, void 0);
console.log(tree);
.as-console-wrapper {
max-height: 100% !important
}

Try something like this by recursive method
var binary = {};
var arr = [8,5,10,3,6,12];
function makeBinary(binary,number){
if(binary.value === undefined){
binary.value = number;
}else if(number > binary.value){
if(binary.right === undefined){
binary.right = {value:number};
}else{
binary.right = makeBinary(binary.right,number);
}
}else{
if(binary.left === undefined){
binary.left = {value:number};
}else{
binary.left = makeBinary(binary.left,number);
}
}
return binary;
}
for(let i in arr){
makeBinary(binary,arr[i]);
}
console.log(binary);

class Node {
constructor(val){
this.val=val;
this.right=null;
this.left=null;
}
}
class Bst{
constructor(){
this.root=null;
}
insert(val){
let newNode= new Node (val)
if (!this.root) this.root=newNode;
let current =this.root;
while (true) {
if(val === current.val) return undefined;
if(current.val<val){
if (current.right===null){
current.right=newNode;
return this
}
else
current=current.right}
if(current.val>val){
if (current.left===null){
current.left=newNode;
return this
}
else
current=current.left}
}
}
print (){
let all="Root=";
let visit=(current=this.root)=>{
if(!current.left && !current.right){
if(all[all.length-1]<current.val)
all+=`,LeR${current.val}`
else
all+=`,LeL${current.val}`
}
else{
if(all[all.length-1]<current.val)
all+=`,FR${current.val}`
else
all+=`,FL${current.val}`
}
if (current.left) visit(current.left)
if (current.right) visit(current.right)
}
visit()
all+=` ,valid bst:${this.isValidBST()}`
return all
}
isValidBST(node=this.root, min = null, max = null) {
if (!node) return true;
if (max !== null && node.data >= max) {
return false;
}
if (min !== null && node.data <= min) {
return false;
}
const leftSide = this.isValidBST(node.left, min, node.data);
const rightSide = this.isValidBST(node.right, node.val, max);
return leftSide && rightSide;
}
find(val){
let found=false
let innerFind=(current=this.root)=>{
if (val>current.val)
if (current.right != null) return innerFind(current.right)
if(val===current.val)
found= true
else
if (current.left != null)return innerFind(current.left)
if(val===current.val)
found= true
return found
}
return innerFind()
}
}
let tree=new Bst
tree.insert(8)
tree.insert(10)
tree.insert(13)
tree.insert(3)
tree.insert(1)
tree.insert(6)
tree.insert(4)
tree.insert(7)
tree.insert(2)
tree.print()

You can do this by technique is called recursion.
make an array with the structure ( left_subtree, key, right_subtree)
in your case
var array = [[3,5,6],8,[null,10,12]
class TreeNode {
constructor(key) {
this.key = key;
this.right = null;
this.left = null;
}
}
function parseTuple(data) {
if (data === null) {
let node = null;
return node;
}
else if (data.length === 3) {
let node = new TreeNode(data[1]);
node.left = parseTuple(data[0]);
node.right = parseTuple(data[2]);
return node;
}
else {
let node = new TreeNode(data);
return node;
}
}

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.

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

Shortest path in a graph in ES6

This is my implementation of a graph, to get the shortest path between A and B.
class Queue {
constructor() {
this.head = null;
this.tail = null;
this.size = 0;
}
offer(item) {
const p = new QueueNode(item);
this.size++;
if (this.head === null) {
this.head = p;
this.tail = p;
return;
}
this.tail.next = p;
this.tail = p;
}
poll() {
if (this.size === 0) {
throw TypeError("Can't deque off an empty queue.");
}
this.size--;
const item = this.head;
this.head = this.head.next;
return item.val;
}
peek() {
if (this.size === 0) {
throw TypeError("Empty Queue.")
}
return this.head.val;
}
isEmpty() {
return this.head === null;
}
}
class QueueNode {
constructor(item) {
this.val = item;
this.next = null;
}
}
class Graph {
constructor(directed = false) {
this.numVertices = 0;
this.directed = directed;
this.dict = {}
}
addEdge(v1, v2, weight = 1) {
let p, q;
if (v1 in this.dict) {
p = this.dict[v1];
} else {
p = new GraphNode(v1);
this.dict[v1] = p;
this.numVertices++;
}
if (v2 in this.dict) {
q = this.dict[v2];
} else {
q = new GraphNode(v2);
this.dict[v2] = q;
this.numVertices++;
}
p.addEdge(q);
if (!this.directed) {
q.addEdge(p);
}
}
stringify() {
for (const [key, value] of Object.entries(this.dict)) {
console.log(`${key}: ${[...value.adjacencySet].map(x => x.data)}`);
}
}
buildDistanceTable(source) {
let p;
if (this.dict[source] === undefined) {
throw TypeError('Vertex not present in graph')
} else {
p = this.dict[source];
}
const distanceTable = {};
for (const [key, value] of Object.entries(this.dict)) {
distanceTable[key] = [-1, -1];
}
distanceTable[p.data] = [0, p.data];
const queue = new Queue();
queue.offer(p);
while (!queue.isEmpty()) {
let curr = queue.poll();
let curr_distance = distanceTable[curr.data][0];
curr.adjacencySet.forEach((item) => {
if (distanceTable[item.data] === -1) {
distanceTable[item.data] = [1 + curr_distance, curr.data];
console.log(distanceTable);
if (item.adjacencySet.length > 0) {
queue.offer(item);
}
}
})
}
return distanceTable;
}
shortestPath(source, destination) {
const distanceTable = this.buildDistanceTable(source);
const path = [destination];
let prev = distanceTable[destination][1];
while (prev !== -1 && prev !== source) {
path.unshift(prev);
prev = distanceTable[prev][1];
}
if (prev === null) {
console.log("There's no path from source to destination");
} else {
path.unshift(source);
path.map(item => {
console.log(item);
});
}
}
}
class GraphNode {
constructor(data) {
this.data = data;
this.adjacencySet = new Set();
}
addEdge(node) {
this.adjacencySet.add(node)
}
}
graph = new Graph(directed = false);
graph.addEdge(0, 1);
graph.addEdge(1, 2);
graph.addEdge(1, 3);
graph.addEdge(2, 3);
graph.addEdge(1, 4);
graph.addEdge(3, 5);
graph.addEdge(5, 4);
graph.addEdge(3, 6);
graph.addEdge(6, 7);
graph.addEdge(0, 7);
graph.stringify();
graph.shortestPath(1, 7);
When I run this it give 1, 7 however that's not the shortest path. What am I doing wrong here.
You have 2 issue in your code (that sabotage the building of the distance table):
You missing index in: if (distanceTable[item.data] === -1) { -> each item in the distance table is of array therefor it need to be: if (distanceTable[item.data][0] === -1) {
Set size in node js checked with size and not length (as in documentation) therefor item.adjacencySet.length is always undefined so you need to change: if (item.adjacencySet.length> 0) { to if (item.adjacencySet.size > 0) {
After those 2 changes your code return me path of 1 -> 0 -> 7
Just small side issue: you missing some ; and "new" before throwing TypeError...

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

Javascript: algorithm to convert Binary search tree to doubly linked list

I am trying to write the algorithm to convert a BST to a doubly linked list. This is what I have so far. Below is the code:
function TreeNode(val) {
this.val = val;
this.left = this.right = null;
}
function BinaryTree() {
this.root = null;
}
BinaryTree.prototype.push = function(val) {
var root = this.root;
if(!root) {
this.root = new TreeNode(val);
return;
}
var currentNode = root;
var newNode = new TreeNode(val);
while(currentNode) {
if (val < currentNode.val) {
if(!currentNode.left) {
currentNode.left = newNode;
break;
} else {
currentNode = currentNode.left;
}
} else if(val > currentNode.val) {
if(!currentNode.right) {
currentNode.right = newNode;
break;
} else {
currentNode = currentNode.right;
}
}
}
}
var bt = new BinaryTree();
bt.push(4);
bt.push(2);
bt.push(5);
bt.push(1);
bt.push(3);
//console.log(bt);
//var node = bt.root;
function Node(node) {
//this.data = value;
//this.previous = this.next = null;
var head = null;
var tail = null;
var prev = null;
console.log(bstToLL(node, head, prev, tail));
}
//function DoublyLinkedList() {
// this.head = null;
// this.prev = null;
// this.tail = null;
//}
function bstToLL(node, head, prev, tail) {
if (node === null) {
return;
}
bstToLL(node.left, head, prev, tail);
if (head === null) {
head = node;
//console.log(head)
}
if (prev === null) {
prev = node;
//console.log(prev)
} else {
//console.log(node);
//console.log(prev);
node.left = prev;
prev.right = node;
}
prev = node
bstToLL(node.right, head, prev, tail);
if(node.right === null) {
tail = node;
}
return head;
}
Node(bt.root);
The code works, but I don't think it is getting the right result. The binary tree looks like-
4
/ \
2 5
/ \
1 3
When I return the head from the bstToLL() method, I get an object with val 4 pointing to right child 5 and left child 2 and so on and so forth.
If you run the code, and check the debugger you will see the head object.
Can someone please guide me if I am doing this the right way, and how to fix the result?
Here is some code which converts a binary tree into a LinkedList. It will log 1, 2, 3, 4, and 5, in order:
function TreeNode(left, value, right) {
this.left = left;
this.value = value;
this.right = right;
}
function ListNode(prev, value, next) {
this.prev = prev;
this.value = value;
this.next = next;
}
function LinkedList(head, tail) {
if (tail === undefined) tail = head;
this.head = head;
this.tail = tail;
}
LinkedList.prototype.addToStart = function(list) {
this.head.prev = list.tail;
list.tail.next = this.head;
this.head = list.head;
}
LinkedList.prototype.addToEnd = function(list) {
this.tail.next = list.head;
list.head.prev = this.tail;
this.tail = list.tail;
};
function bstToLL(tree) {
var centerNode = new ListNode(null, tree.value, null);
var list = new LinkedList(centerNode);
if (tree.left) list.addToStart(bstToLL(tree.left));
if (tree.right) list.addToEnd(bstToLL(tree.right));
return list;
}
var tree = new TreeNode(
new TreeNode(
new TreeNode(null, 1, null),
2,
new TreeNode(null, 3, null)
),
4,
new TreeNode(null, 5, null)
);
var linkedList = bstToLL(tree);
for (var node = linkedList.head; node; node = node.next) console.log(node.value);

Categories