Recursion and Binary Search Trees in Javascript

Joseph Harwood
4 min readSep 22, 2019

--

Recursion

Recursion is the process in which a function calls itself directly or indirectly. A recursive function is a function that calls itself during its execution.

A simple example of a recursive function:

const factorial = (n) => {
if (n === 1) {
return 1
}
else {
return n * factorial(n-1)
}
}

Every recursive function needs to have the simplest solution provided for the base case.

if (n === 1) {
return 1
}

The solution to the bigger problems are shown in smaller problems.

else {
return n * factorial(n-1)
}

As you can see, the base case for getting the factorial of n would be 1 and the bigger problems have a recursive call of the factorial recursive method until n is equal to 1.

Let’s show what this recursive call looks like:

const factorial = (n) => {
if (n === 1) {
console.log("n " + n);
return 1
}
else {
console.log("n " + n);
return n * factorial(n-1)
}
}
console.log(factorial(5));
console.log(factorial(1));

Output:

n: 5n: 4n: 3n: 2n: 1120n: 11

factorial(5) recursively calls factorial(n-1) until it reaches 1 and factorial(1) hits the base case and immediately returns 1.

Now that we have completed a simple example, let’s look at practical applications used with the Binary Search Tree data structure.

Binary Search Tree

A Binary Search Tree is a node-based binary tree data structure which has the following properties:

  • The left subtree of a node contains only nodes with keys lesser than the node’s key.
  • The right subtree of a node contains only nodes with keys greater than the node’s key.
  • The left and right subtree each must also be a binary search tree.

BSTs get an average case of O(log n) on gets, adds, and deletes, but they can have a worst case of O(n) if you add a sorted list (like [1, 2, 3, 4, 5) to a BST.

1
\
2
\
3
\
4
\
5

Let’s define a BST that looks like this graphic:

const tree = {
"value": 8,
"left": {
"value": 3,
"left": {
"value": 1,
"left": null,
"right": null
},
"right": {
"value": 6,
"left": {
"value": 4,
"left": null,
"right": null
},
"right": {
"value": 7,
"left": null,
"right": null
}
}
},
"right": {
"value": 10,
"left": null,
"right": {
"value": 14,
"left": {
"value": 13,
"left": null,
"right": null
},
"right": null
}
}
}

Depth-first Traversal

Depth-first traversal has the deepest node of the BST visited and then backtracks to its parent node if no sibling of that node exist. There are three types of depth-first traversal.

  • Preorder traversal — you process the node, then recursively call the method on the left subtree and then the right subtree.
  • Inorder traversal — you first recursively call the method on the left tree, then process the node, and then call the method on the right tree.
  • Postorder traversal — you recursively call the method on the left subtree, then the left subtree, then you process the node.

How it looks in Javascript:

const preorderTraverse = (node, array) => {
if (!node) return array;
array.push(node.value);
array = preorderTraverse(node.left, array);
array = preorderTraverse(node.right, array);
return array;
};
const inorderTraverse = (node, array) => {
if (!node) return array;
array = inorderTraverse(node.left, array);
array.push(node.value);
array = inorderTraverse(node.right, array);
return array;
};
const postorderTraverse = (node, array) => {
if (!node) return array;
array = postorderTraverse(node.left, array);
array = postorderTraverse(node.right, array);
array.push(node.value);
return array;
};
console.log(preorderTraverse(tree, []));
console.log(inorderTraverse(tree, []));
console.log(postorderTraverse(tree, []));

Output:

// Preorder
[8, 3, 1, 6, 4, 7, 10, 14, 13]
// Inorder
[1, 3, 5, 6, 7, 8, 10, 13, 14]
// Postorder
[1, 4, 7, 6, 3, 13, 14, 10, 8]

The base case in these recursive methods is if (!node) return array; and the left and right branches of each node are recursively called with array = inorderTraverse(node.left, array); and array = inorderTraverse(node.right, array);. Recursion makes traversing the BST much easier than doing it iteratively.

Other Recursion Examples with BSTs:

const minNode = (node) => {
if(!node){
return 0;
}
if(node.left){
return minNode(node.left)
}
return node.value
}
const maxNode = (node) => {
if(!node){
return 0;
}
if(node.right){
return maxNode(node.right)
}
return node.value;
}
const contains = (node, value) => {
if (!node) {
return false
}
if (node.value === value) {
return true
}
else if (value < node.value) {
return contains(node.left, value)
}
else {
return contains(node.right, value)
}
}
console.log(minNode(tree));
console.log(maxNode(tree));
console.log(contains(tree, 10));

Output:

114truefalse

Thanks for reading!

--

--

No responses yet