Finding the Inorder Successor in a Binary Search Tree (BST)
Problem Description
Given a binary search tree (BST) and one of its nodes p, find the inorder successor of that node (i.e., the node that appears immediately after p in the inorder traversal sequence). It is assumed that each node contains a val (value), left (left child), right (right child), and parent pointer. If p has no successor, return null.
Solution Process
Step 1: Understanding Inorder Traversal and the Definition of a Successor
- The inorder traversal result of a binary search tree is an ascending ordered sequence.
- The successor node of
pis the smallest node that appears afterpin the inorder traversal. - Example: For an inorder traversal
[2, 3, 5, 7, 9], ifp=5, the successor is7; ifp=9, the successor isnull.
Step 2: Analyzing Possible Locations of the Successor Node
The location of the successor node falls into two cases:
-
phas a right subtree:- The successor is the leftmost node in
p's right subtree (i.e., the minimum node in the right subtree). - Reason: After visiting
pin an inorder traversal, the leftmost branch of its right subtree is traversed immediately. - Example: If
p's right child isr, start fromrand keep moving left until reaching a leaf node.
- The successor is the leftmost node in
-
phas no right subtree:- The successor is an ancestor of
pwhere this ancestor is the left child of its own parent. - Reason: After finishing visiting
p, the traversal backtracks to the first ancestor whose "right subtree has not been processed." - Search method: Starting from
p, traverse upwards until finding a nodexsuch thatpis located in the left subtree ofx. Thisxis the successor.
- The successor is an ancestor of
Step 3: Algorithm Implementation
- If
p.right != null:- Start from
p.rightand traverse leftwards continuously, returning the deepest left child node.
- Start from
- If
p.right == null:- Start from
pand traverse upwards until finding a nodexthat satisfies the condition thatpis the left child ofx(i.e.,x.left == p). - If the root is reached without finding such a node, it means
pis the last node, so returnnull.
- Start from
Step 4: Code Example (with Detailed Comments)
def find_inorder_successor(p):
if not p:
return None
# Case 1: p has a right subtree
if p.right:
node = p.right
while node.left: # Find the leftmost node in the right subtree
node = node.left
return node
# Case 2: p has no right subtree
else:
# Traverse upwards to find the first ancestor where p is in its left subtree
node = p
while node.parent and node.parent.right == node:
node = node.parent # If p is the right child of its parent, continue upwards
return node.parent # At this point, node's parent is the successor
Step 5: Example Verification
Take the following BST as an example (parent pointers are in parentheses):
5 (null)
/ \
3 (5) 8 (5)
/ \ / \
2 (3) 6 (8) 9 (8)
\ \
4 (3) 7 (6)
- If
p=4(no right subtree): Move up to3(4is the right child of3), then continue up to5(3is the left child of5). The successor is5. - If
p=5(has a right subtree): Enter the right subtree8, then move left to find6. The successor is6. - If
p=9(no right subtree): Move up to8(9is the right child of8), then continue up to5(8is the right child of5). No qualifying ancestor is found, so returnnull.
Key Points Summary
- Using the parent pointer allows efficient backtracking to ancestor nodes. Without the parent pointer, the tree must be traversed from the root again (time complexity increases to O(n)).
- The algorithm has an average time complexity of O(log n), and O(n) in the worst case (when the tree degenerates into a linked list).