BST - Deletion
#include <bits/stdc++.h> // Includes common standard libraries (iostream, queue, etc.)
using namespace std; // Use the standard namespace
// Definition of a Node in the Binary Search Treeclass Node {public: int data; // Data value of the node Node* left; // Pointer to the left child Node* right; // Pointer to the right child
// Constructor to initialize a new node Node(int data) { this->data = data; this->left = NULL; // Initially, left child is NULL this->right = NULL; // Initially, right child is NULL }};
// Function to insert a new node with 'data' into the BSTNode* insertIntoBST(Node* root, int data) { if(root == NULL) { root = new Node(data); return root; }
if(data > root->data) { root->right = insertIntoBST(root->right, data); } else { // Handles duplicates by placing them on the left root->left = insertIntoBST(root->left, data); }
return root;}
// Function to take input from the user and build the BSTvoid takeinput(Node* &root) { int data; cout << "Enter data for node (enter -1 to stop): "; cin >> data;
while(data != -1) { root = insertIntoBST(root, data); cout << "Enter data for node (enter -1 to stop): "; cin >> data; }}
// Function to perform Level Order Traversal (BFS) of the BSTvoid levelOrderTraversal(Node* root) { if(root == NULL) { cout << "Tree is empty." << endl; return; }
queue<Node*> Q; Q.push(root); Q.push(NULL); // Marker for end of level
while(!Q.empty()) { Node* FrontNode = Q.front(); Q.pop();
if(FrontNode == NULL) { cout << endl; // Newline for next level
if(!Q.empty()) { // If queue is not empty, push another NULL marker Q.push(NULL); } } else { cout << FrontNode->data << " "; // Print node data
if(FrontNode->left) { Q.push(FrontNode->left); }
if(FrontNode->right) { Q.push(FrontNode->right); } } }}
// Helper function to find the minimum value in a subtree// (used to find the in-order successor for deletion)int minVal(Node* root) { if(root == NULL) { return -1; // Or throw an error, depending on desired error handling } Node* temp = root; while(temp->left != NULL) { temp = temp->left; } return temp->data;}
// Function to delete a node with specific 'data' from the BST recursively.// Returns the root of the modified subtree.// Time Complexity: O(H) (height of the tree)// Space Complexity: O(H) (recursion stack)Node* DeletionInBST(Node* root, int data) { // Base Case 1: If the current subtree is empty, node not found. if(root == NULL) { return root; }
// If the current node is the one to be deleted if(root->data == data) { // Case 1: 0 Child (Leaf Node) if(root->left == NULL && root->right == NULL) { delete root; // Free memory return NULL; // Return NULL to its parent }
// Case 2: 1 Child // Subcase A: Has Left Child only if(root->left != NULL && root->right == NULL) { Node* temp = root->left; // Store left child delete root; // Delete current node return temp; // Return left child to parent } // Subcase B: Has Right Child only if(root->left == NULL && root->right != NULL) { Node* temp = root->right; // Store right child delete root; // Delete current node return temp; // Return right child to parent }
// Case 3: 2 Children if(root->left != NULL && root->right != NULL) { // Find the in-order successor (smallest in right subtree) int successor_val = minVal(root->right);
// Replace current node's data with successor's data root->data = successor_val;
// Recursively delete the successor from the right subtree root->right = DeletionInBST(root->right, successor_val);
return root; // Return current node (now with successor's data) } } // If the current node is NOT the one to be deleted, // traverse left or right based on BST property else if(data > root->data) { // If data is greater, go to right subtree root->right = DeletionInBST(root->right, data); return root; } else { // data < root->data // If data is smaller, go to left subtree root->left = DeletionInBST(root->left, data); return root; } return root; // Should not be reached if all cases are covered.}
int main() { Node* root = NULL; int key_to_delete;
cout << "--- Creating Binary Search Tree ---" << endl; takeinput(root); // Build the initial BST
cout << endl << "Before Deletion (Level Order Traversal) : " << endl; levelOrderTraversal(root); // Print tree before deletion
cout << endl << "Enter the key to delete : "; cin >> key_to_delete; // Get the key to delete from user
// Perform deletion and update the root of the tree root = DeletionInBST(root, key_to_delete);
cout << endl << "After Deletion (Level Order Traversal) : " << endl; levelOrderTraversal(root); // Print tree after deletion
return 0;}
/*Example INPUT for tree creation:50 20 70 10 30 60 80 -1
Initial Tree (Level Order):5020 7010 30 60 80
Scenario 1: Delete a Leaf Node (e.g., 10)Enter the key to delete : 10After Deletion (Level Order Traversal) :5020 7030 60 80
Scenario 2: Delete a Node with 1 Child (e.g., 70, which has 60 and 80)Let's rebuild and try deleting 70 from the original tree (70 has right child 80 if 60 wasn't inserted to left, or if 60 was inserted as right child of 70 (which is wrong BST property)).With input 50 20 70 10 30 60 80 -1, 70 has 60 (left) and 80 (right) children. So it's 2-child case.Let's use a tree where 70 has only one child, e.g., 50 20 70 10 30 80 -1 (no 60).Tree: 50 / \ 20 70 / \ \ 10 30 80Enter the key to delete : 70After Deletion (Level Order Traversal) :5020 8010 30
Scenario 3: Delete a Node with 2 Children (e.g., 50)Enter the key to delete : 50Original Tree: 50 / \ 20 70 / \ / \ 10 30 60 80In-order successor of 50 is 60 (min of right subtree).After Deletion (Level Order Traversal) :6020 7010 30 80*/
1. Binary Search Tree (BST) Recap
- A Binary Search Tree (BST) maintains a specific ordering: values in the left subtree are less than the root, and values in the right subtree are greater than the root. This property is crucial for insertion, search, and deletion.
2. Supporting Functions (Briefly)
Node
class: Defines the structure of a BST node (data
,left
,right
).insertIntoBST
: Standard recursive function to add elements to the BST.takeinput
: Utility to build the BST from user input.levelOrderTraversal
: Utility to print the tree level by level, helpful for verifying deletions.minVal
: Helper function to find the minimum value in a subtree. This is used in the 2-child deletion case. It finds the leftmost node.
3. DeletionInBST(Node* root, int data)
Function (Recursive Deletion)
-
Purpose: Removes a node with the specified
data
value from the BST while preserving its properties. -
Core Idea: Deletion is complex because it must maintain the BST ordering. The strategy depends on how many children the node to be deleted has.
-
Logic Flow:
-
Base Case (Node Not Found):
- If
root == NULL
, the tree (or current subtree) is empty, or thedata
was not found. ReturnNULL
.
- If
-
Node Found (
root->data == data
): This is the node to delete. Now, handle the 3 cases:-
Case 1: Node has 0 children (Leaf Node)
- Condition:
root->left == NULL && root->right == NULL
- Action:
delete root;
(free memory). - Return:
NULL
(to set the parent’s pointer to this node toNULL
).
- Condition:
-
Case 2: Node has 1 Child
- Subcase A: Has Left Child Only
- Condition:
root->left != NULL && root->right == NULL
- Action: Store
root->left
in a temporary pointer (Node* temp = root->left;
).delete root;
. - Return:
temp
(the left child becomes the new connection for the parent of the deleted node).
- Condition:
- Subcase B: Has Right Child Only
- Condition:
root->left == NULL && root->right != NULL
- Action: Store
root->right
in a temporary pointer (Node* temp = root->right;
).delete root;
. - Return:
temp
(the right child becomes the new connection for the parent of the deleted node).
- Condition:
- Subcase A: Has Left Child Only
-
Case 3: Node has 2 Children
- Condition:
root->left != NULL && root->right != NULL
- Strategy: To maintain BST properties, the deleted node must be replaced by either its in-order successor (smallest node in its right subtree) or its in-order predecessor (largest node in its left subtree).
- Code’s Approach (In-order Successor):
- Find the minimum value in the right subtree:
int mini = minVal(root->right);
. Thismini
is the in-order successor. - Replace the
data
of the currentroot
(the node to be deleted) withmini
:root->data = mini;
. - Recursively call
DeletionInBST
on the right subtree to delete the original in-order successor node (mini
’s original location):root->right = DeletionInBST(root->right, mini);
. The successor node is guaranteed to have at most one child (a right child), simplifying its deletion. - Return:
root
(the current node, which now contains the successor’s data).
- Find the minimum value in the right subtree:
- Condition:
-
-
Recursive Search (Node Not Yet Found):
- If
data > root->data
: The node to delete is in the right subtree. Recursively callDeletionInBST(root->right, data)
and assign the result back toroot->right
. Then, returnroot
. - If
data < root->data
: The node to delete is in the left subtree. Recursively callDeletionInBST(root->left, data)
and assign the result back toroot->left
. Then, returnroot
.
- If
-
4. Complexity Analysis for Deletion
- Time Complexity:
O(H)
H
is the height of the BST. In the worst case, searching for the node and then searching for the in-order successor both involve traversing down paths proportional to the height.- Best Case (Balanced BST):
H = log N
. So,O(log N)
. - Worst Case (Skewed BST/Linear Chain):
H = N
. So,O(N)
.
- Space Complexity:
O(H)
- Due to the recursion call stack.