Binary Search Trees with JavaScript
By: Chad Murobayashi
Tags: JavaScript, Algorithms, Software Development, Binary Search Tree, Data Structures

Trees, Binary Trees, and Binary Search Trees

Before we dive into Binary Search Trees, let’s first learn about trees and binary trees.

A tree is a data structure that consists of nodes with a parent and child relationship. Every tree can have only one root node (which is the uppermost node). Each node can have any number of child nodes. Keep in mind however that each node can only have one parent node (except for the root node which will not have a parent node). In the image below, the node with a value of 2 is our root node. 2, then has two children, 7 and 5. 7, then has three children, 2, 10, and 6, etc.

Binary Trees are a type of tree, where each node can have at most two child nodes. In the image below, you can see that each node has either 0, 1, or 2 child nodes.

Binary Search Trees are a type of Binary Tree that has sorted data. These can be useful for searching or insertion. The rule for Binary Search Trees is that for each parent node, every value on the left side must be less than the parent, and every value on the right side must be greater than the parent. In the image below, we can see that 8 (our root node) has two children, 3 and 10. On the left side, 3 is less than 8, and on the right side, 10 is greater than 8. We can then look at each node and do the same check going down the tree.

For Binary Search Trees, keep in mind that every value to the left must be less than the parent, and every value to the right must be greater than the parent. For example, in the image above, if we changed the node with a value of 7, to 9, this would not be a valid Binary Search Tree, because 9 would be greater than 8. Remember, every node value on the left side of 8, must be less than 8, and every node value on the right side must be greater.

Building a Binary Search Tree

First, let’s create our Node class and Binary Search Tree class. Our Node class constructor will take in a value, and we will set that as the value of the node. Then we will set left and right values to be null. Our Binary Search Tree class will have a root value which we will set to null.

class Node {

constructor(value) {

this.value = value;

this.left = null;

this.right = null;

}

} class BinarySearchTree {

constructor() {

this.root = null;

}

}

Inserting a Node

Let’s now handle how to insert nodes into our tree. We will create an insert method to our Binary Search Tree class which will take in a value. First, we will create a new Node with that value. There is one edge case, which is if the tree is empty (there is no root), then we will set the root of the tree to be the new node, return the tree, and we are done.

insert(value) {

const newNode = new Node(value);

if (!this.root) {

this.root = newNode;

return this;

}

Otherwise, we need to compare the value of the new node, to the value of the root. Let’s first create a current variable to keep track of the node we are comparing to. Then, we will first handle the left side, in the case of which the value of the new node is less than the value of the current node.

We will set up a while loop, to continue to compare the new node value to the current node value. Once we insert the node in the correct spot in the tree, we can break out of the loop by returning the tree. If the current node does not have a left value, we will set the value as the new node and return the tree. Else, we need to update the current node to be the left node (remember, the current node is what we are comparing to).

insert(value) {

const newNode = new Node(value);

if (!this.root) {

this.root = newNode;

return this;

} else {

let current = this.root;

while(true) {

if (value < current.value) {

if (!current.left) {

current.left = newNode;

return this;

} else {

current = current.left

}

Then we need to handle the right side, in the case where the new node is greater than the current node. We will do the same checks as above, except for the right side. If there is no right node, we will set the right node to be the new node and return the tree. Else, we will update the current node to be the right node.

insert(value) {

const newNode = new Node(value);

if (!this.root) {

this.root = newNode;

return this;

} else {

let current = this.root;

while(true) {

if (value < current.value) {

if (!current.left) {

current.left = newNode;

return this;

} else {

current = current.left;

}

} else if (value > current.value) {

if (!current.right) {

current.right = newNode;

return this;

} else {

current = current.right;

}

}

}

}

}

In our example above, we are checking if the new node value is less than the current value and if the new node value is greater than the current value. But what if the new node value is equal to a value already in the tree? There are different ways to handle this, but in our example, we will simply return undefined. Let’s add this line of code below as the first check for our while loop.

if (value === current.value) return undefined;

The final code should look something like this.

Finding a Node

The second method we will add to our Binary Search Tree class is how to check if a value exists in our tree. Let’s name this method find, and it will take in a value as the argument. This value will be what we are searching for in our tree. Similar to the insert method, we will first check if our tree is empty (there is no root). If so, then we will simply return undefined.

find(value) {

if (!this.root) return undefined;

}

Otherwise, we will be handling this with a while loop. To start we will create two variables, current, and found. The current variable will be to help us keep track of our position in the tree, and the found variable will be to let us know if we find the value.

Our while loop will run as long as there is a current value, and we have not found the node. We will break out of our loop in two cases:

If we find the node, we will set found to be true. If there is no current value, it means our tree does not contain the node.

Let’s first check if the value we are searching for is less than the current value. If so, we will move to the left in our tree by setting the current value to current.left. Then we will do the same thing for the right side. If the value we are searching for is greater than the current value, we will set the current to current.right. Finally, if the value is equal to the current value, we have found our node and we will set found equal to true.

After our while loop, we will do one final check. If found is still equal to false, this means the value is not in our tree and we will return undefined. Else, we will return the node with the value we were searching for by returning current.

find(value) {

if (!this.root) return undefined;

let current = this.root;

let found = false;

while(current && !found) {

if (value < current.value) {

current = current.left;

} else if (value > current.value) {

current = current.right;

} else {

found = true;

}

}

if (!found) return undefined;

return current;

}

Our final code, with both, insert and find methods, is below. In the last line of the code, we are creating a new Binary Search Tree as the variable, tree. Now you can insert values into the tree using tree.insert(value) and check if the tree contains a value using tree.find(value).