Discover how a smart tree can find the closest smaller value faster than scanning everything!
Why BST Inorder Predecessor in DSA Python?
Imagine you have a messy stack of books sorted by height, but you want to find the book just shorter than a specific one. Without a system, you have to check each book one by one, which takes a lot of time and effort.
Manually searching for the book just shorter than another means scanning through all books, comparing heights repeatedly. This is slow and easy to make mistakes, especially if the stack is large or not perfectly ordered.
A Binary Search Tree (BST) organizes data so you can quickly find the item just smaller than a given one, called the inorder predecessor. It uses the tree's structure to jump directly to the right spot without checking everything.
def find_predecessor_manual(books, target): smaller_books = [b for b in books if b < target] if not smaller_books: return None return max(smaller_books)
def find_inorder_predecessor(root, target): predecessor = None current = root while current: if target > current.value: predecessor = current current = current.right else: current = current.left return predecessor
This lets you quickly find the closest smaller value in sorted data, enabling fast lookups and efficient data handling.
In a contact list sorted by names, finding the contact just before a given name helps in quick navigation or autocomplete suggestions.
Manual search is slow and error-prone for predecessor finding.
BST structure allows fast, direct access to inorder predecessor.
Efficient predecessor search improves many real-world applications like databases and search engines.
Practice
Solution
Step 1: Understand inorder traversal order
Inorder traversal visits nodes in ascending order for BST, so predecessor is the previous node in this order.Step 2: Define inorder predecessor
The inorder predecessor is the node with the largest value smaller than the current node's value.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
Solution
Step 1: Identify inorder predecessor logic for left subtree
If node has left child, predecessor is the rightmost node in left subtree.Step 2: Check code correctness
Code D moves to left child, then goes right as far as possible, correctly finding predecessor.Final Answer:
Code snippet D correctly finds the inorder predecessor -> Option DQuick Check:
Left subtree's rightmost node = predecessor [OK]
- Going right subtree instead of left
- Going left repeatedly instead of right in left subtree
- Returning left child directly without traversal
20
/ \
10 30
\ \
15 40
Solution
Step 1: Locate node 15 and check left subtree
Node 15 has no left child, so predecessor is ancestor smaller than 15.Step 2: Find nearest ancestor smaller than 15
Ancestor 10 is smaller than 15 and is the closest on path to root.Final Answer:
10 -> Option CQuick Check:
Predecessor of 15 is 10 [OK]
- Choosing 20 which is larger
- Choosing node itself as predecessor
- Assuming predecessor is None without checking ancestors
def inorder_predecessor(root, node):
if node.left:
temp = node.left
while temp.left:
temp = temp.left
return temp
else:
predecessor = None
while root:
if node.val > root.val:
predecessor = root
root = root.right
else:
root = root.left
return predecessor
Solution
Step 1: Analyze left subtree traversal
In left subtree, predecessor is rightmost node, so loop should go right, not left.Step 2: Identify correct traversal direction
Changing while temp.left to while temp.right fixes the bug.Final Answer:
The while loop should check temp.right, not temp.left -> Option BQuick Check:
Predecessor in left subtree = rightmost node [OK]
- Looping left instead of right in left subtree
- Ignoring else block logic
- Not returning predecessor correctly
Solution
Step 1: Understand no left child case
If node has no left child, predecessor is an ancestor smaller than node.Step 2: Use root traversal to track predecessor
Traverse from root, update predecessor when node value is greater than root's value.Step 3: Return last tracked smaller ancestor
This gives the inorder predecessor correctly.Final Answer:
Traverse from root, track the last node smaller than current node -> Option AQuick Check:
No left child -> track smaller ancestor [OK]
- Returning parent without checking value
- Returning left child when none exists
- Trying to find predecessor in left subtree when none exists
Ready to prove it?
Pass the test and this pattern moves unknown
