Skip to the content.

Introduction to Binary Search Trees

The most extensive use of binary trees is for search and indexing applications where elements are from a totally ordered set. It is based on the idea of making search faster by the principle of exclusion and inclusion like binary search.It supports the following set of operations as most of the other data structures:

The average time complexity of any operation is

The figure below provides an example of a binary search tree.

The link or tree branch label indicates the relationships between the elements stored at end nodes. All elements in the right subtree of 50 are greater than 50. Likewise, all elements in the left subtree of 50 are smaller than 50. The node structure of a BST remains the same as that of a binary tree.

The most frequent operation on a BST is searching. Search is essentially a traversal of the tree. It terminates either successfully or reporting that the element does not exist. The search works as follows:

Insertion operation also uses search. After insertion the tree must satisfy the BST property. So the position where insertion of an element e should occur would be between a pair of elements e1 and e2 such that:

Inserting e into an empty tree is simple, it just returns a pointer to the new node containing e. For insertion into a non-empty tree, we find the position in the left subtree if the element at the current node is larger than e; otherwise, we search for the appropriate position in the right subtree of the current node. The insertion function appears below:

TNODE * insert(TNODE * node, int info) {
    if (node == NULL) // Insert first node
        return newNode(info); 
    if (info < node->info)
        // Insert into left subtree
        node->left = insert(node->left, info); 
    else if (info > node->info)
        // Insert into right subtree
        node->right = insert(node->right, info);
    return node; 
}

The deletion operation is a bit involved. We need to handle three cases:

Case 1 can be handled by deleting the concerned leaf node. It does not affect the rest of the tree. The figure below illustrates this case. Double circles indicate the leaf nodes.

Case 2 can be handled simply by promoting the child of the node to be deleted to the parent’s position. The subtree below is unaffected. Since the child occupies the position of its previous parent, the absence of the parent node does not affect the rest of the tree. This case is illustrated below. The nodes having one child are indicated by double circles in the figure below.

Case 3 is little involved. We need to find the inorder successor or the inorder predecessor of the node to be deleted. For consistency in description, we will use inorder successor. The node is swapped with the inorder successor. Then the node is deleted from the new position. Either case 1 or case 2 would apply to the problem of deleting the node at a new position. So, we need to prove that inorder successor is either a leaf node or a node with one child. Before proceeding with the proof, examine the figure below , which illustrates case 3. All internal nodes having two children are marked by double circles in the figures below

The inorder successor of a node is the leftmost node in the node’s right subtree to be deleted. If the successor is not a leaf node, then it can only have a right child because the presence of a left child would mean the node identified as the inorder successor is not correct. It cannot be the leftmost node in the node’s right subtree to be deleted. The deletion function is given below.

TNODE * deleteNode(TNODE * root, int x) {
    TNODE * temp;
    if (root == NULL) {
        printf("Error: empty tree or element not present\n");
        return root;
    }
 
    // If element is smaller than that at the root delete from the left subtree
    if (x < root->info)
        root->left = deleteNode(root->left, x);
 
    // If element is bigger than the element at the root delete from the right subtree
    else if (x > root->info)
        root->right = deleteNode(root->right, x);
 
    // If element at the root equal to element to be deleted, delete the root. 
    else {
        // Node has only one child or no child
        if (root->left == NULL) {
            temp = root->right;
            printf("Delete %d success\n",root->info);
            free(root);
            return temp;
        }
        else if (root->right == NULL) {
            temp = root->left;
            printf("Delete %d success\n",root->info);
            free(root);
            return temp;
        }
 
        // For a node with two children get the inorder successor
        // Inorder successor is the smallest node in the right subtree
        
        temp = smallestNode(root->right);
 
        // Copy the inorder successor's content to this node
        root->info = temp->info;
 
        // Delete the inorder successor, recursive call will take care of the applicable case
        root->right = deleteNode(root->right, temp->info);
    }
    return root;
} 

Source Code for BST

Back to Index