Trees
BST Search
Search a binary search tree for one present and one absent value.
Algorithm
The canonical tree is 4(2(1,3),6(5,7)), so this Rust DSA
implementation can be compared directly with the rest of the DSA track.
search path
A comparison chooses one subtree at each step, so whole branches are skipped.
Visual walkthrough
Basic Implementation
basic.rs
use std::collections::VecDeque;
struct Node { value: i32, left: Option<Box<Node>>, right: Option<Box<Node>> }
impl Node {
fn new(value: i32) -> Self { Self { value, left: None, right: None } }
fn with(value: i32, left: Node, right: Node) -> Self {
Self { value, left: Some(Box::new(left)), right: Some(Box::new(right)) }
}
}
fn render(node: &Option<Box<Node>>) -> String {
match node {
None => "_".to_string(),
Some(n) => {
if n.left.is_none() && n.right.is_none() { n.value.to_string() }
else { format!("{}({},{})", n.value, render(&n.left), render(&n.right)) }
}
}
}
fn sample_tree() -> Option<Box<Node>> {
Some(Box::new(Node::with(4, Node::with(2, Node::new(1), Node::new(3)), Node::with(6, Node::new(5), Node::new(7)))))
}
fn list_string(values: &[i32]) -> String {
format!("[{}]", values.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))
}
fn search(root: &Option<Box<Node>>, target: i32) -> bool { let mut node = root.as_ref(); while let Some(n) = node { if target == n.value { return true; } node = if target < n.value { n.left.as_ref() } else { n.right.as_ref() }; } false }
fn main() { let root = sample_tree(); println!("{}", if search(&root, 5) { "5 found" } else { "5 not found" }); println!("{}", if search(&root, 8) { "8 found" } else { "8 not found" }); }
Complexity
- Time: O(h) per search
- Space: O(1) iterative
Implementation notes
- Rust stores child links as
Option<Box<Node>>, withNonefor an empty child andSome(Box<Node>)owning each subtree. sample_tree()builds the searched tree withNode::withandNode::new, returningOption<Box<Node>>for4(2(1,3),6(5,7)).search(root: &Option<Box<Node>>, target: i32) -> boolborrows the tree read-only and returns a boolean result, not a node or index.- The cursor starts as
let mut node = root.as_ref(), convertingOption<Box<Node>>intoOption<&Box<Node>>without moving ownership. while let Some(n) = nodereads the current node. Equality returnstrue; otherwise the branch expression reborrows eithern.left.as_ref()orn.right.as_ref().- The trace searches
5by visiting4and branching right, visiting6and branching left, then matching at5. - Searching
8visits4,6, and7, branches right each time, then reaches a null cursor and returnsfalse. This lesson has no separate imbalance contrast; the miss path is the visible boundary in the trace. mainprints display-formatted string literals selected by the boolean return:5 foundand8 not found.