Bird
Raised Fist0
DSA Rustprogramming

BST Inorder Predecessor in DSA Rust

Choose your learning style10 modes available
Mental Model
The inorder predecessor of a node in a BST is the node with the next smaller value when we list all nodes in order.
Analogy: Imagine a sorted list of books on a shelf. The inorder predecessor of a book is the book just before it on the shelf.
      5
     / \
    3   7
   / \   \
  2   4   8
 ↑curr
Dry Run Walkthrough
Input: BST: 5 -> 3 -> 7 -> 2 -> 4 -> 8, find inorder predecessor of node with value 5
Goal: Find the node with the largest value smaller than 5 in the BST
Step 1: Start at node 5, check if left child exists
      5[↑curr]
     / \
    3   7
   / \   \
  2   4   8
Why: We look to the left subtree to find smaller values than 5
Step 2: Move to left child 3, then go right as far as possible
      5
     / \
    3[↑curr] 7
   / \   \
  2   4   8
Why: The inorder predecessor is the rightmost node in left subtree
Step 3: Move from 3 to its right child 4, which has no right child
      5
     / \
    3   7
   / \   \
  2   4[↑curr] 8
Why: 4 is the largest node smaller than 5, so it is the predecessor
Result:
      5
     / \
    3   7
   / \   \
  2   4[predecessor] 8
Answer: 4
Annotated Code
DSA Rust
use std::rc::Rc;
use std::cell::RefCell;

#[derive(Debug, Clone)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    pub fn new(val: i32) -> Rc<RefCell<TreeNode>> {
        Rc::new(RefCell::new(TreeNode { val, left: None, right: None }))
    }
}

fn inorder_predecessor(root: Option<Rc<RefCell<TreeNode>>>, key: i32) -> Option<i32> {
    let mut predecessor = None;
    let mut curr = root.clone();

    // Find the node with value == key
    while let Some(node_rc) = curr.clone() {
        let node = node_rc.borrow();
        if key <= node.val {
            curr = node.left.clone(); // move left if key smaller or equal
        } else {
            predecessor = Some(node.val); // update predecessor
            curr = node.right.clone(); // move right to find closer smaller
        }
    }

    // If predecessor found, return it
    predecessor
}

fn main() {
    // Build BST manually
    let root = TreeNode::new(5);
    let node3 = TreeNode::new(3);
    let node7 = TreeNode::new(7);
    let node2 = TreeNode::new(2);
    let node4 = TreeNode::new(4);
    let node8 = TreeNode::new(8);

    root.borrow_mut().left = Some(node3.clone());
    root.borrow_mut().right = Some(node7.clone());
    node3.borrow_mut().left = Some(node2.clone());
    node3.borrow_mut().right = Some(node4.clone());
    node7.borrow_mut().right = Some(node8.clone());

    let key = 5;
    let pred = inorder_predecessor(Some(root.clone()), key);
    match pred {
        Some(val) => println!("Inorder predecessor of {} is {}", key, val),
        None => println!("No inorder predecessor found for {}", key),
    }
}
while let Some(node_rc) = curr.clone() {
Traverse the tree to find the predecessor candidate
if key <= node.val { curr = node.left.clone(); } else { predecessor = Some(node.val); curr = node.right.clone(); }
If current node value is smaller than key, update predecessor and go right; else go left
OutputSuccess
Inorder predecessor of 5 is 4
Complexity Analysis
Time: O(h) because we traverse from root down to a leaf where h is tree height
Space: O(1) because we use only a few variables, no extra data structures
vs Alternative: Naive approach would do full inorder traversal O(n), this uses BST property to do it in O(h)
Edge Cases
Key is smallest node (no predecessor)
Returns None because no smaller node exists
DSA Rust
if key <= node.val { curr = node.left.clone(); }
Key not present in tree
Returns predecessor of closest smaller node if any, else None
DSA Rust
while let Some(node_rc) = curr.clone() { ... }
Tree with single node
Returns None as no predecessor exists
DSA Rust
if key <= node.val { curr = node.left.clone(); }
When to Use This Pattern
When asked for the previous smaller value in BST order, use the inorder predecessor pattern by searching left subtree or tracking last smaller node.
Common Mistakes
Mistake: Trying to find predecessor by full inorder traversal and then searching array
Fix: Use BST property to move left or right and track predecessor without full traversal
Mistake: Not updating predecessor when moving right
Fix: Update predecessor when current node value is less than key before moving right
Summary
Finds the node with the largest value smaller than the given key in a BST.
Use when you need the immediate smaller value than a node in BST order.
The key insight is to move left if node value is >= key, else update predecessor and move right.

Practice

(1/5)
1. What is the inorder predecessor of a node in a Binary Search Tree (BST)?
easy
A. The node with the largest value smaller than the given node
B. The node with the smallest value larger than the given node
C. The left child of the given node
D. The right child of the given node

Solution

  1. Step 1: Understand BST property

    In a BST, left subtree nodes are smaller and right subtree nodes are larger than the current node.
  2. Step 2: Define inorder predecessor

    The inorder predecessor is the node visited just before the current node in an inorder traversal, which means it has the largest value smaller than the current node.
  3. Final Answer:

    The node with the largest value smaller than the given node -> Option A
  4. Quick Check:

    Inorder predecessor = largest smaller value [OK]
Hint: Inorder predecessor is largest smaller node [OK]
Common Mistakes:
  • Confusing predecessor with successor
  • Choosing child nodes directly without checking values
  • Thinking predecessor is always left child
2. Which Rust code snippet correctly finds the inorder predecessor of a node with a left subtree in a BST?
easy
A. let pred = node.right.clone();
B. let mut pred = node.right.as_ref(); while let Some(left) = pred.unwrap().left.as_ref() { pred = Some(left); }
C. let mut pred = node.left.as_ref(); while let Some(right) = pred.unwrap().right.as_ref() { pred = Some(right); }
D. let pred = node.left.clone();

Solution

  1. Step 1: Identify left subtree traversal

    The inorder predecessor is the rightmost node in the left subtree, so start from node.left.
  2. Step 2: Traverse to rightmost node

    Keep moving to the right child until no more right child exists to find the largest node in left subtree.
  3. Final Answer:

    let mut pred = node.left.as_ref(); while let Some(right) = pred.unwrap().right.as_ref() { pred = Some(right); } -> Option C
  4. Quick Check:

    Traverse left subtree rightmost node = let mut pred = node.left.as_ref(); while let Some(right) = pred.unwrap().right.as_ref() { pred = Some(right); } [OK]
Hint: Go left once, then right as far as possible [OK]
Common Mistakes:
  • Starting from right subtree instead of left
  • Not looping to the rightmost node
  • Using clone instead of reference traversal
3. Given the BST below and node value 15, what is the inorder predecessor?

       20
      /  \
    10    30
      \     \
      15    40
medium
A. 30
B. 15
C. 20
D. 10

Solution

  1. Step 1: Locate node 15 and its left subtree

    Node 15 has no left child, so we look for the ancestor smaller than 15.
  2. Step 2: Find largest ancestor smaller than 15

    10 is the parent of 15 and smaller than 15, so 10 is the inorder predecessor.
  3. Final Answer:

    10 -> Option D
  4. Quick Check:

    Largest smaller ancestor = 10 [OK]
Hint: If no left child, go up to smaller ancestor [OK]
Common Mistakes:
  • Choosing node itself as predecessor
  • Choosing larger ancestor incorrectly
  • Ignoring no left subtree case
4. Identify the bug in this Rust function to find the inorder predecessor of a BST node:

fn inorder_predecessor(node: &Option) -> Option<i32> {
    let mut current = node.as_ref()?.left.as_ref();
    while current?.right.is_some() {
        current = current?.right.as_ref();
    }
    current.map(|n| n.val)
}
medium
A. Using '?' operator on Option without handling None case
B. Starting from node.right instead of node.left
C. Returning node.val instead of predecessor value
D. Not checking if node has left child before traversal

Solution

  1. Step 1: Analyze use of '?' operator in loop condition

    The '?' operator unwraps Option or returns None; using it inside while condition causes panic if None.
  2. Step 2: Identify safe way to traverse Option references

    Must use pattern matching or if let to safely unwrap Options instead of '?' in loop condition.
  3. Final Answer:

    Using '?' operator on Option without handling None case -> Option A
  4. Quick Check:

    Unsafe '?' in loop condition causes panic [OK]
Hint: Avoid '?' in loop conditions on Option [OK]
Common Mistakes:
  • Using '?' inside loops causing runtime panic
  • Ignoring None cases in Option traversal
  • Confusing left and right subtree
5. You want to find the inorder predecessor of a node in a BST that has no left child. Which approach correctly finds it?
hard
A. Return the rightmost node in the right subtree
B. Traverse up the tree to find the nearest ancestor whose right child is also an ancestor of the node
C. Return the leftmost node in the right subtree
D. Return the root node always

Solution

  1. Step 1: Understand no left child case

    If node has no left child, predecessor is not in left subtree but among ancestors.
  2. Step 2: Find nearest ancestor where node is in right subtree

    Traverse up until you find an ancestor whose right child is also an ancestor of the node; that ancestor is the predecessor.
  3. Final Answer:

    Traverse up the tree to find the nearest ancestor whose right child is also an ancestor of the node -> Option B
  4. Quick Check:

    No left child -> find right-side ancestor [OK]
Hint: Go up to ancestor where node is in right subtree [OK]
Common Mistakes:
  • Returning nodes from right subtree incorrectly
  • Always returning root node
  • Ignoring ancestor traversal
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard