BST Inorder Predecessor in DSA C - Time & Space Complexity
We want to understand how long it takes to find the inorder predecessor in a Binary Search Tree (BST).
The question is: how does the time grow as the tree gets bigger?
Analyze the time complexity of the following code snippet.
// Find inorder predecessor in BST
Node* inorderPredecessor(Node* root, Node* node) {
if (node->left != NULL) {
Node* temp = node->left;
while (temp->right != NULL) {
temp = temp->right;
}
return temp;
}
Node* predecessor = NULL;
Node* ancestor = root;
while (ancestor != node) {
if (node->data > ancestor->data) {
predecessor = ancestor;
ancestor = ancestor->right;
} else {
ancestor = ancestor->left;
}
}
return predecessor;
}
This code finds the inorder predecessor of a given node in a BST by checking left subtree or ancestors.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Traversing down the tree using while loops.
- How many times: At most, the loops run once each, moving down the tree height.
As the tree grows taller, the number of steps to find the predecessor grows roughly with the tree height.
| Input Size (n) | Approx. Operations (tree height h) |
|---|---|
| 10 | Up to 4-5 steps (if balanced) |
| 100 | Up to 7 steps (if balanced) |
| 1000 | Up to 10 steps (if balanced) |
Pattern observation: The steps grow slowly, roughly proportional to the tree height, not total nodes.
Time Complexity: O(h)
This means the time depends on the height of the tree, which is the longest path from root to leaf.
[X] Wrong: "Finding the inorder predecessor always takes time proportional to the total number of nodes."
[OK] Correct: The search only moves down the tree height, not all nodes, so it depends on height, not total nodes.
Understanding how tree height affects search time helps you explain efficient tree operations clearly in interviews.
"What if the BST is unbalanced and looks like a linked list? How would the time complexity change?"
Practice
Solution
Step 1: Understand inorder traversal in BST
Inorder traversal visits nodes in ascending order of their values.Step 2: Define inorder predecessor
The inorder predecessor of a node is the node visited just before it in inorder traversal, which means it has the largest value smaller than the current node.Final Answer:
The node with the largest value smaller than the given node -> Option AQuick Check:
Inorder predecessor = largest smaller value [OK]
- Confusing predecessor with successor
- Thinking predecessor is always left child
- Assuming predecessor is the parent node
node in a BST when the node has a left subtree?Solution
Step 1: Identify inorder predecessor in left subtree
If node has a left child, predecessor is the rightmost node in left subtree.Step 2: Trace code logic
Starting from node->left, moving right until right child is NULL finds the rightmost node.Final Answer:
Node* pred = node->left; while (pred->right != NULL) pred = pred->right; -> Option AQuick Check:
Left subtree's rightmost node = predecessor [OK]
- Going right subtree instead of left
- Moving left repeatedly instead of right
- Starting from node->right instead of node->left
20
/ \
10 30
\ \
15 40
Solution
Step 1: Locate node 15 and check left subtree
Node 15 has no left child, so predecessor is an ancestor smaller than 15.Step 2: Find nearest ancestor smaller than 15
Ancestor 10 is smaller than 15 and is the closest on the path to root.Final Answer:
10 -> Option DQuick Check:
Predecessor of 15 is 10 [OK]
- Choosing node itself as predecessor
- Choosing larger ancestor like 20
- Confusing predecessor with successor
Node* inorderPredecessor(Node* root, Node* node) {
if (node->left != NULL) {
Node* pred = node->left;
while (pred->left != NULL) {
pred = pred->left;
}
return pred;
}
Node* pred = NULL;
Node* ancestor = root;
while (ancestor != node) {
if (node->data > ancestor->data) {
pred = ancestor;
ancestor = ancestor->right;
} else {
ancestor = ancestor->left;
}
}
return pred;
}
What is the main error in this code?Solution
Step 1: Analyze left subtree traversal
In left subtree, predecessor is rightmost node, so loop should move right, not left.Step 2: Check code loop
Code incorrectly moves left repeatedly, so it finds leftmost node instead of rightmost.Final Answer:
The while loop should move right in left subtree, not left -> Option CQuick Check:
Left subtree traversal must go right for predecessor [OK]
- Moving left instead of right in left subtree
- Ignoring ancestor traversal logic
- Assuming predecessor is always left child
node that has no left child. Which approach correctly finds the predecessor?Solution
Step 1: Understand no left child case
If node has no left child, predecessor is an ancestor where node is in right subtree.Step 2: Use parent pointers to find such ancestor
Move up until current node is right child of its parent; that parent is predecessor.Final Answer:
Move up using parent pointers until you find a node which is right child of its parent; then return that parent -> Option BQuick Check:
Go up to right-child parent for predecessor [OK]
- Stopping at left child parent
- Returning sibling nodes incorrectly
- Assuming predecessor is always child node
Ready to prove it?
Pass the test and this pattern moves unknown
