Implementation of Binary Search Tree in Javascript

In this article, we would be implementing the Binary Search Tree data structure in Javascript. A tree is a a collection of node connected by some edges. A tree is a non linear data structure. A Binary Search tree is a binary tree in which nodes which have lesser value are stored on the left while the nodes with higher value are stored at the right.
Now lets see an example of of an Binary Search Tree node:

filter_none

edit
close

play_arrow

link
brightness_4
code

// Node class
class Node
{
    constructor(data)
    {
        this.data = data;
        this.left = null;
        this.right = null;
    }
}

chevron_right


As in the above code snippet we define a node class having three property data, left and right, Left and right are pointers to the left and right node in a Binary Search Tree. Data is initialized with data which is passed when object for this node is created and left and right is set to null.

Now lets see an example of an Binary Search Tree class.



filter_none

edit
close

play_arrow

link
brightness_4
code

// Binary Search tree class
class BinarySearchTree
{
    constructor()
    {
        // root of a binary seach tree
        this.root = null;
    }
  
    // function to be implemented
    // insert(data)
    // remove(data)
                  
  
    // Helper function
    // findMinNode()
    // getRootNode()
    // inorder(node)
    // preorder(node)               
    // postorder(node)
    // search(node, data)
}

chevron_right


The above example shows a framework of a Binary Search tree class, which contains a private variable root which holds the root of a tree, it is initialized to null.
Now lets implement each of this function:

  1. insert(data) – It inserts a new node in a tree with a value data
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // helper method which creates a new node to 
    // be inserted and calls insertNode
    insert(data)
    {
        // Creating a node and initailising 
        // with data 
        var newNode = new Node(data);
                          
        // root is null then node will
        // be added to the tree and made root.
        if(this.root === null)
            this.root = newNode;
        else
      
            // find the correct position in the 
            // tree and add the node
            this.insertNode(this.root, newNode);
    }
      
    // Method to insert a node in a tree
    // it moves over the tree to find the location
    // to insert a node with a given data 
    insertNode(node, newNode)
    {
        // if the data is less than the node
        // data move left of the tree 
        if(newNode.data < node.data)
        {
            // if left is null insert node here
            if(node.left === null)
                node.left = newNode;
            else
      
                // if left is not null recurr until 
                // null is found
                this.insertNode(node.left, newNode); 
        }
      
        // if the data is more than the node
        // data move right of the tree 
        else
        {
            // if right is null insert node here
            if(node.right === null)
                node.right = newNode;
            else
      
                // if right is not null recurr until 
                // null is found
                this.insertNode(node.right,newNode);
        }
    }

    chevron_right

    
    

    In the above code we have two methods insert(data) and insertNode(node, newNode). Lets understand them one by one:-

    • insert(data) – It creates a new node with a value data, if the tree is empty it add this node to tree and make it a root, otherwise it calls insert(node, data).
    • insert(node, data) – It compares the given data with the data of current node and moves left or right accordingly and recur until it finds a correct node with a null value where new node can be added.
  2. remove(data) – This function removes a node with a given data.
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // helper method that calls the 
    // removeNode with a given data
    remove(data)
    {
        // root is re-initialized with
        // root of a modified tree.
        this.root = this.removeNode(this.root, data);
    }
      
    // Method to remove node with a 
    // given data
    // it recurrs over the tree to find the
    // data and removes it
    removeNode(node, key)
    {
              
        // if the root is null then tree is 
        // empty
        if(node === null)
            return null;
      
        // if data to be delete is less than 
        // roots data then move to left subtree
        else if(key < node.data)
        {
            node.left = this.removeNode(node.left, key);
            return node;
        }
      
        // if data to be delete is greater than 
        // roots data then move to right subtree
        else if(key > node.data)
        {
            node.right = this.removeNode(node.right, key);
            return node;
        }
      
        // if data is similar to the root's data 
        // then delete this node
        else
        {
             // deleting node with no children
            if(node.left === null && node.right === null)
            {
                node = null;
                return node;
            }
      
            // deleting node with one children
            if(node.left === null)
            {
                node = node.right;
                return node;
            }
              
            else if(node.right === null)
            {
                node = node.left;
                return node;
            }
      
            // Deleting node with two children
            // minumum node of the rigt subtree
            // is stored in aux
            var aux = this.findMinNode(node.right);
            node.data = aux.data;
      
            node.right = this.removeNode(node.right, aux.data);
            return node;
        }
      
    }

    chevron_right

    
    

    In the above code we have two method remove(data) and removeNode(node, data), let understand them one by one:

    • remove(data) – It is helper methods which calls removeNode by passing root node and given data and updates the root of the tree with the value returned by the function
    • removeNode(node, data) – It searches for a node with a given data and then perform certain steps to delete it.

    While deleting a node from the tree their are three different scenarios as follows:-

    • Deleting the leaf node – As leaf node do not have any children hence they can be easily removed and null is returned to the parent node
    • Deleting a node with one child – If a node have a left child then we update the pointer of the parent node to the left child of the node to be deleted and similarly if a node have a right child then we update the pointer of the parent node to the right child of the node to be deleted
    • Deleting a node with two children – In order to delete a node with two children we find the node with minimum value in its right subtree and replace this node with the minimum valued node and remove the minimum valued node from the tree

    In the above code we have used findMinNode(node), it is defined in a helper method section.
    Recommendation: Binary Search Tree | Set 2 (Delete) It contains a detail explaination and a video tutorial for deleting a node from binary search tree.

Tree Traversal

Now Lets understand different ways of traversing a Binary Search Tree.

  1. inorder(node) – It performs inorder traversal of a tree starting from a given node
    Algorithm for inorder:

    1. Traverse the left subtree i.e perform inorder on left subtree
    2. Visit the root
    3. Traverse the right subtree i.e perform inorder on right subtree
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // Performs inorder traversal of a tree
    inorder(node)
    {
        if(node !== null)
        {
            this.inorder(node.left);
            console.log(node.data);
            this.inorder(node.right);
        }
    }

    chevron_right

    
    

  2. preorder(node) – It performs preorder traversal of a tree starting from a given node.
    Algorithm for preoder:

    1. Visit the root
    2. Traverse the left subtree i.e perform inorder on left subtree
    3. Traverse the right subtree i.e perform inorder on right subtree
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // Performs preorder traversal of a tree    
    preorder(node)
    {
        if(node != null)
        {
            console.log(node.data);
            this.preorder(node.left);
            this.preorder(node.right);
        }
    }

    chevron_right

    
    

  3. postorder(node) – It performs postorder traversal of a tree starting from a given node.
    Algorithm for postorder:

    1. Traverse the left subtree i.e perform inorder on left subtree
    2. Traverse the right subtree i.e perform inorder on right subtree
    3. Visit the root
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // Performs postorder traversal of a tree
    postorder(node)
    {
        if(node != null)
        {
            this.postorder(node.left);
            this.postorder(node.right);
            console.log(node.data);
        }
    }

    chevron_right

    
    

Helper Methods


Lets declare some helper method which are useful while working with Binary Search Tree.

  1. findMinNode(node) – It searches for a node with a minimum value starting from node.
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    //  finds the minimum node in tree
    // searching starts from given node
    findMinNode(node)
    {
        // if left of a node is null
        // then it must be minimum node
        if(node.left === null)
            return node;
        else
            return this.findMinNode(node.left);
    }

    chevron_right

    
    

    As seen in the above method we start from a node and keeping moving to the left subtree until we find a node whose left child is null, once we find such node we return it.

  2. getRootNode() – It returns the root node of a tree.
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // returns root of the tree
    getRootNode()
    {
        return this.root;
    }

    chevron_right

    
    

  3. search(data) – It searches the node with a value data in the entire tree.
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // search for a node with given data
    search(node, data)
    {
       // if trees is empty return null
        if(node === null)
            return null;
      
        // if data is less than node's data
        // move left
        else if(data < node.data)
            return this.search(node.left, data);
      
        // if data is less than node's data
        // move left
        else if(data > node.data)
            return this.search(node.right, data);
      
        // if data is equal to the node data 
        // return node
        else
            return node;
    }

    chevron_right

    
    

Note : Different helper method can be declared in the BinarySearchTree class as per the requirement.
Implementation
Now lets use the BinarySearchTree class and its different methods described above.

filter_none

edit
close

play_arrow

link
brightness_4
code

// create an object for the BinarySearchTree
var BST = new BinarySearchTree();
  
// Inserting nodes to the BinarySearchTree
BST.insert(15);
BST.insert(25);
BST.insert(10);
BST.insert(7);
BST.insert(22);
BST.insert(17);
BST.insert(13);
BST.insert(5);
BST.insert(9);
BST.insert(27);
                          
//          15
//         /  \
//        10   25
//       / \   / \
//      7  13 22  27
//     / \    /
//    5   9  17 
  
var root = BST.getRootNode();
              
// prints 5 7 9 10 13 15 17 22 25 27
BST.inorder(root);
              
// Removing node with no children 
BST.remove(5);
              
              
//          15
//         /  \
//        10   25
//       / \   / \
//      7  13 22  27
//       \    /
//        9  17 
              
                          
var root = BST.getRootNode();
              
// prints 7 9 10 13 15 17 22 25 27
BST.inorder(root);
              
// Removing node with one children 
BST.remove(7);
              
//          15
//         /  \
//        10   25
//       / \   / \
//      9  13 22  27
//            /
//           17 
              
              
var root = BST.getRootNode();
  
// prints 9 10 13 15 17 22 25 27
BST.inorder(root);
              
// Removing node with two children 
BST.remove(15);
      
//          17
//         /  \
//        10   25
//       / \   / \
//      9  13 22  27
  
var root = BST.getRootNode();
console.log("inorder traversal");
  
// prints 9 10 13 17 22 25 27
BST.inorder(root);
              
console.log("postorder traversal");
BST.postorder(root);
console.log("preorder traversal");
BST.preorder(root);

chevron_right


For more on binary trees please refer to the following article: Binary tree Data Structure

This article is contributed by Sumit Ghosh. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.



My Personal Notes arrow_drop_up


Article Tags :
Practice Tags :


4


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.