Binary Search Tree Validation

  • Verify if a binary tree is a valid BST (binary search tree)
  • nodes in left subtree are lower than node
  • nodes in right subtree are greater than node

The point:

  • Recursive
  • DFS

Complexity :

Time Space
O(n) O(n)
  • O(n) in time because we traverse each node exactly once
  • O(n) in space because of the size of the recursive stack which can grow as large as the heigh of binary tree (n at its max.)

About Rust :

  • Based on V2 (see 189_intro.ipynb) for easy tree building
  • YES : tested on the Rust Playground

V1

type Link = Option<Box<TreeNode>>;

struct TreeNode {
    value: i32,
    left: Link,
    right: Link,
}

impl TreeNode {
    fn new(value: i32) -> Self {
        TreeNode {
            value,
            left: None,
            right: None,
        }
    }

    // Add child on the left
    fn left(mut self, node: TreeNode) -> Self {
        self.left = Some(Box::new(node));
        self
    }

    // Add child on the right
    fn right(mut self, node: TreeNode) -> Self {
        self.right = Some(Box::new(node));
        self
    }
}

fn is_within_bounds(link: &Link, lower_bound:i32, upper_bound:i32) -> bool {
    if let Some(node) = link {
        // if current node value not within the bounds, this is not a valid BST
        if node.value>=upper_bound || node.value<=lower_bound{
            return false
        }
        // If left subtree not a valid BST, this is not a valid BST
        if !is_within_bounds(&node.left, lower_bound, node.value){
            return false
        }
        // Otherwise returns true if the right subtree is a valid BST
        is_within_bounds(&node.right, node.value, upper_bound)
    } else {
        // base case, there is no node. BST condition is satisfied
        true
    }
}

fn binary_search_tree_validation(link: & Link)-> bool{
    is_within_bounds(link, i32::MIN, i32::MAX)
}

fn preorder_print(link: &Link) {
    if let Some(node) = link {
        print!("{} ", node.value);      // Process current node
        preorder_print(&node.left);     // Traverse left child
        preorder_print(&node.right);    // Traverse right child
    }
}

fn main() { // no main() if this code runs in a Jupyter cell 
    // Build the tree:
    //        5
    //      /   \
    //     2     7
    //    / \   / \
    //   1   6 7   9
    let tree = TreeNode::new(5)
        .left(
            TreeNode::new(2)
                .left(
                    TreeNode::new(1)
                )
                .right(
                    TreeNode::new(6)
                )
        )
        .right(
            TreeNode::new(7)
                .left(
                    TreeNode::new(7)
                )
                .right(
                    TreeNode::new(9)
                )
        );

    let root_link = Some(Box::new(tree));
    preorder_print(&root_link); // 5 2 1 6 7 7 9    
    println!("\n{:?}", binary_search_tree_validation(& root_link)); // false
} // end of local scope OR end of main()

V2

  • Preferred solution?
type Link = Option<Box<TreeNode>>;

struct TreeNode {
    value: i32,
    left: Link,
    right: Link,
}

impl TreeNode {
    fn new(value: i32) -> Self {
        TreeNode {
            value,
            left: None,
            right: None,
        }
    }

    // Add child on the left
    fn left(mut self, node: TreeNode) -> Self {
        self.left = Some(Box::new(node));
        self
    }

    // Add child on the right
    fn right(mut self, node: TreeNode) -> Self {
        self.right = Some(Box::new(node));
        self
    }
}

fn is_within_bounds(link: &Link, lower_bound: i32, upper_bound: i32) -> bool {
    match link {
        Some(node) => {
            let value = node.value;
            // If current node's value is out of valid bounds, this is not a valid BST
            if value <= lower_bound || value >= upper_bound {
                return false;
            }
            // Recursively check the left and right subtrees
            is_within_bounds(&node.left, lower_bound, value) && is_within_bounds(&node.right, value, upper_bound)
        }
        None => true, // Empty subtree is valid
    }
}

fn binary_search_tree_validation(link: & Link)-> bool{
    is_within_bounds(link, i32::MIN, i32::MAX)
}

fn preorder_print(link: &Link) {
    if let Some(node) = link {
        print!("{} ", node.value);      // Process current node
        preorder_print(&node.left);     // Traverse left child
        preorder_print(&node.right);    // Traverse right child
    }
}

fn main() { // no main() if this code runs in a Jupyter cell 
    // Build the tree:
    //        5
    //      /   \
    //     2     7
    //    / \   / \
    //   1   6 7   9
    let tree = TreeNode::new(5)
        .left(
            TreeNode::new(2)
                .left(
                    TreeNode::new(1)
                )
                .right(
                    TreeNode::new(6)
                )
        )
        .right(
            TreeNode::new(7)
                .left(
                    TreeNode::new(7)
                )
                .right(
                    TreeNode::new(9)
                )
        );


    let root_link = Some(Box::new(tree));
    preorder_print(&root_link); // 5 2 1 6 7 7 9    
    println!("\n{:?}", binary_search_tree_validation(& root_link)); // false
} // end of local scope OR end of main()

Copy-past the code below to return true (valid BST)

fn main() { // no main() if this code runs in a Jupyter cell 
    // Build the tree:
    //        5
    //      /   \
    //     3     8
    //    / \   / \
    //   1   4 7   9
    let tree = TreeNode::new(5)
        .left(
            TreeNode::new(3)
                .left(
                    TreeNode::new(1)
                )
                .right(
                    TreeNode::new(4)
                )
        )
        .right(
            TreeNode::new(8)
                .left(
                    TreeNode::new(7)
                )
                .right(
                    TreeNode::new(9)
                )
        );

    let root_link = Some(Box::new(tree));
    preorder_print(&root_link); // 5 3 1 4 8 7 9    
    println!("\n{:?}", binary_search_tree_validation(& root_link)); // true
} // end of local scope OR end of main()

Back to top

Published on: Jun 22 2025 at 09:00 AM | Last updated: Jun 22 2025 at 09:00 AM

Copyright © 1964-2025 - 40tude