Trees
BST Insert
Insert values into a binary search tree by comparing at each node.
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.
binary search tree
Values smaller than a node go left; larger values go right.
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 insert(root: &mut Option<Box<Node>>, value: i32) { match root { None => *root = Some(Box::new(Node::new(value))), Some(node) => if value < node.value { insert(&mut node.left, value) } else { insert(&mut node.right, value) } } }
fn main() { let mut root = None; for value in [4, 2, 6, 1, 3, 5, 7] { insert(&mut root, value); } println!("{}", render(&root)); }
Complexity
- Time: O(h) per insert
- Space: O(n)
Implementation notes
- Rust stores each child as
Option<Box<Node>>:struct Node { value: i32, left: Option<Box<Node>>, right: Option<Box<Node>> }.Nonerepresents an empty child andSome(Box<Node>)owns the subtree. Node::new(value)creates a leaf withleft: Noneandright: None; insertion allocates withSome(Box::new(Node::new(value)))when it reaches an empty slot.insert(root: &mut Option<Box<Node>>, value: i32)mutably borrows the slot to update. Matching onrooteither fillsNoneor recurses into&mut node.left/&mut node.right.- The branch is
if value < node.value; duplicates would follow theelsebranch into the right subtree, though this checked insertion order has no duplicates. mainstarts withlet mut root = Noneand inserts[4, 2, 6, 1, 3, 5, 7], mutating the same owned tree rather than returning a new root.- The trace records tree states after each insert:
4,4(2,_),4(2,6),4(2(1,_),6),4(2(1,3),6),4(2(1,3),6(5,_)), then4(2(1,3),6(5,7)). render(&root)borrows the tree and formats_forNone, leaf values as bare numbers, and interior nodes asvalue(left,right).println!("{}", ...)prints4(2(1,3),6(5,7)).- The replay also includes the sorted-insert contrast
1(_,2(_,3(_,4))), showing this ownership model still degrades to height4and O(n) cost without rotations.