Binary Search Trees (BST): Insertion, Deletion, and Inorder/Preorder/Postorder Traversals in C

Author: Bhuban Subedi | Subject: Data Structures and Algorithms (CACS201) | Semester: Third Semester


In non-linear data structures, the Binary Search Tree (BST) is one of the most elegant and efficient concepts in computer science.

While searching through a linked list requires linear $O(N)$ time, a balanced Binary Search Tree reduces searching, insertion, and deletion times down to logarithmic $O(\log N)$ time by recursively halving the search space—similar to binary search in arrays.

In the Tribhuvan University (TU) BCA Third Semester DSA (CACS201) board examination, questions requiring you to construct a BST from a sequence of keys, perform tree traversals, or write the C function for deleting a node with two children appear consistently in 10-mark long questions.

In this guide, we will master the mathematical properties of BSTs, visualize recursive traversals, handle all three deletion cases, and write complete compilable C code.


1. What Is a Binary Search Tree (BST)?

A Binary Tree is a tree data structure in which each parent node has at most two children (referred to as the left child and right child).

A Binary Search Tree (BST) is a special binary tree that strictly satisfies the BST Ordering Property:
1. All keys stored in the left subtree of a node must be strictly less than ($<$) the node’s key.
2. All keys stored in the right subtree of a node must be strictly greater than ($>$) the node’s key.
3. Both the left and right subtrees must also be valid Binary Search Trees (recursive definition).

                     [ 50 ]  <-- Root
                    /      \
               [ 30 ]      [ 70 ]
              /      \    /      \
          [ 20 ]   [ 40 ][ 60 ]  [ 80 ]

2. Tree Traversals: Inorder, Preorder, and Postorder

Tree traversal refers to visiting every node in the tree exactly once in a systematic sequence.

+-------------------+---------------------------+--------------------------------------+
| Traversal Name    | Recursive Sequence        | Unique Property                      |
+-------------------+---------------------------+--------------------------------------+
| **Inorder**       | `Left -> Root -> Right`   | **Always produces sorted order** for |
|                   |                           | any valid Binary Search Tree!        |
+-------------------+---------------------------+--------------------------------------+
| **Preorder**      | `Root -> Left -> Right`   | Used to clone / serialize trees.     |
+-------------------+---------------------------+--------------------------------------+
| **Postorder**     | `Left -> Right -> Root`   | Used in bottom-up deletion & postfix |
|                   |                           | mathematical tree evaluations.       |
+-------------------+---------------------------+--------------------------------------+

Trace on Example Tree:

For the tree shown above:
Inorder ($L \rightarrow V \rightarrow R$): 20, 30, 40, 50, 60, 70, 80 (Ascending Sorted!)
Preorder ($V \rightarrow L \rightarrow R$): 50, 30, 20, 40, 70, 60, 80
Postorder ($L \rightarrow R \rightarrow V$): 20, 40, 30, 60, 80, 70, 50


3. Node Deletion in BST: The 3 Critical Cases

While insertion is straightforward recursion, deleting a node from a BST requires careful structural restructuring to preserve the BST property.

       +-------------------------------------------------------------+
       |                  DELETION CASES IN A BST                    |
       +-------------------------------------------------------------+
       | Case 1: Node is a Leaf (0 children)                        |
       |         Simply free memory and set parent link to NULL.     |
       +-------------------------------------------------------------+
       | Case 2: Node has 1 Child (Left OR Right)                   |
       |         Bypass the node: Link parent directly to the child. |
       +-------------------------------------------------------------+
       | Case 3: Node has 2 Children                                |
       |         Find Inorder Successor (smallest in right subtree). |
       |         Copy Successor's value into current node.           |
       |         Recursively delete the Inorder Successor node.      |
       +-------------------------------------------------------------+

4. Complete C Implementation: Binary Search Tree

#include <stdio.h>
#include <stdlib.h>

// BST Node Structure
struct TreeNode {
    int key;
    struct TreeNode *left;
    struct TreeNode *right;
};

// Function prototypes
struct TreeNode* createNode(int item);
struct TreeNode* insert(struct TreeNode *node, int key);
struct TreeNode* search(struct TreeNode *root, int key);
struct TreeNode* findMin(struct TreeNode *node);
struct TreeNode* deleteNode(struct TreeNode *root, int key);
void inorder(struct TreeNode *root);
void preorder(struct TreeNode *root);
void postorder(struct TreeNode *root);

int main() {
    struct TreeNode *root = NULL;

    printf("--- BINARY SEARCH TREE (BST) MASTER DEMO ---\n");

    // Construct BST by inserting keys
    int keys[] = {50, 30, 70, 20, 40, 60, 80};
    int n = sizeof(keys) / sizeof(keys[0]);

    for (int i = 0; i < n; i++) {
        root = insert(root, keys[i]);
    }

    printf("\n1. Inorder Traversal (Sorted Order):\n");
    inorder(root);
    printf("\n");

    printf("\n2. Preorder Traversal (Root First):\n");
    preorder(root);
    printf("\n");

    printf("\n3. Postorder Traversal (Bottom Up):\n");
    postorder(root);
    printf("\n");

    // Search Demo
    int searchVal = 40;
    if (search(root, searchVal) != NULL) {
        printf("\n>> Search: Key %d FOUND in BST!\n", searchVal);
    } else {
        printf("\n>> Search: Key %d NOT found.\n", searchVal);
    }

    // Deletion Demo: Delete node with 2 children (Node 50 - Root)
    printf("\nDeleting Root Node (50) which has 2 children...\n");
    root = deleteNode(root, 50);

    printf("Inorder Traversal after deleting 50:\n");
    inorder(root);
    printf("\n");

    return 0;
}

// Create new tree node
struct TreeNode* createNode(int item) {
    struct TreeNode *temp = (struct TreeNode*) malloc(sizeof(struct TreeNode));
    temp->key = item;
    temp->left = temp->right = NULL;
    return temp;
}

// Recursive BST Insertion
struct TreeNode* insert(struct TreeNode *node, int key) {
    if (node == NULL) {
        return createNode(key);
    }
    if (key < node->key) {
        node->left = insert(node->left, key);
    } else if (key > node->key) {
        node->right = insert(node->right, key);
    }
    return node;
}

// Search a key in BST
struct TreeNode* search(struct TreeNode *root, int key) {
    if (root == NULL || root->key == key) {
        return root;
    }
    if (key < root->key) {
        return search(root->left, key);
    }
    return search(root->right, key);
}

// Find minimum node (leftmost leaf) in a subtree
struct TreeNode* findMin(struct TreeNode *node) {
    struct TreeNode *curr = node;
    while (curr && curr->left != NULL) {
        curr = curr->left;
    }
    return curr;
}

// Delete a node from BST
struct TreeNode* deleteNode(struct TreeNode *root, int key) {
    if (root == NULL) return root;

    if (key < root->key) {
        root->left = deleteNode(root->left, key);
    } else if (key > root->key) {
        root->right = deleteNode(root->right, key);
    } else {
        // Node found! Handle the 3 cases:

        // Case 1 & 2: 0 or 1 child
        if (root->left == NULL) {
            struct TreeNode *temp = root->right;
            free(root);
            return temp;
        } else if (root->right == NULL) {
            struct TreeNode *temp = root->left;
            free(root);
            return temp;
        }

        // Case 3: 2 children
        // Get Inorder Successor (smallest in the right subtree)
        struct TreeNode *temp = findMin(root->right);

        // Copy successor's key to this node
        root->key = temp->key;

        // Delete the inorder successor from right subtree
        root->right = deleteNode(root->right, temp->key);
    }
    return root;
}

// Traversals
void inorder(struct TreeNode *root) {
    if (root != NULL) {
        inorder(root->left);
        printf("%d ", root->key);
        inorder(root->right);
    }
}

void preorder(struct TreeNode *root) {
    if (root != NULL) {
        printf("%d ", root->key);
        preorder(root->left);
        preorder(root->right);
    }
}

void postorder(struct TreeNode *root) {
    if (root != NULL) {
        postorder(root->left);
        postorder(root->right);
        printf("%d ", root->key);
    }
}

5. Time Complexity Analysis

+---------------+-----------------------+-----------------------+
| Operation     | Average Case (Balanced| Worst Case (Skewed)   |
+---------------+-----------------------+-----------------------+
| Search        | $O(\log N)$           | $O(N)$                |
| Insertion     | $O(\log N)$           | $O(N)$                |
| Deletion      | $O(\log N)$           | $O(N)$                |
| Traversal     | $O(N)$                | $O(N)$                |
+---------------+-----------------------+-----------------------+

Why does Skewing happen? If you insert already sorted keys (e.g., 10, 20, 30, 40, 50) into a normal BST, the tree degenerates into a single long branch (a degenerate/skewed tree) resembling a linked list, degrading search performance to $O(N)$. In Semester 3 DSA, self-balancing trees like AVL Trees solve this with automatic rotations.


Frequently Asked Questions (FAQ)

Q1: What is the Inorder Successor of a node in a BST?

The Inorder Successor of a node is the node with the smallest key that is strictly greater than the given node’s key. In a tree with a right subtree, it is simply the leftmost child in the right subtree.

Q2: What is the maximum number of nodes in a binary tree of height $h$?

A binary tree of height $h$ (where root is height 0) can have at most $2^{h+1} – 1$ nodes.

LEAVE A REPLY

Please enter your comment!
Please enter your name here