Trees
Preorder Traversal
Visit the root before each subtree, producing root-left-right order.
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.
preorder
Preorder records the current node before visiting left and right subtrees.
Basic Implementation
basic.rs
Replay: real traced execution (multi-file project)
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 preorder(node: &Option<Box<Node>>, output: &mut Vec<i32>) {
if let Some(n) = node {
output.push(n.value);
preorder(&n.left, output);
preorder(&n.right, output);
}
}
fn main() {
let root = sample_tree();
let mut output = Vec::new();
preorder(&root, &mut output);
println!("{}", list_string(&output));
}
tree ← 4(2(1,3),6(5,7)), output ← []
36fn sample_tree() -> Option<Box<Node>> {37 Some(Box::new(Node::with(values this step4(2(1,3),6(5,7))tree[]outputoutput ← [4]
56if let Some(n) = node {57 output.push(n.value);58 preorder(&n.left, output);values this step[] → [4]output4nodeoutput ← [4, 2]
56if let Some(n) = node {57 output.push(n.value);58 preorder(&n.left, output);values this step[4] → [4, 2]output2nodeoutput ← [4, 2, 1]
56if let Some(n) = node {57 output.push(n.value);58 preorder(&n.left, output);values this step[4, 2] → [4, 2, 1]output1nodeoutput ← [4, 2, 1, 3]
56if let Some(n) = node {57 output.push(n.value);58 preorder(&n.left, output);values this step[4, 2, 1] → [4, 2, 1, 3]output3nodeoutput ← [4, 2, 1, 3, 6]
56if let Some(n) = node {57 output.push(n.value);58 preorder(&n.left, output);values this step[4, 2, 1, 3] → [4, 2, 1, 3, 6]output6nodeoutput ← [4, 2, 1, 3, 6, 5]
56if let Some(n) = node {57 output.push(n.value);58 preorder(&n.left, output);values this step[4, 2, 1, 3, 6] → [4, 2, 1, 3, 6, 5]output5nodeoutput ← [4, 2, 1, 3, 6, 5, 7]
56if let Some(n) = node {57 output.push(n.value);58 preorder(&n.left, output);values this step[4, 2, 1, 3, 6, 5] → [4, 2, 1, 3, 6, 5, 7]output7nodeprintln!("{}", list_string(&output));
66 preorder(&root, &mut output);67 println!("{}", list_string(&output));68}values this step[4, 2, 1, 3, 6, 5, 7]output
Complexity
- Time: O(n)
- Space: O(h) recursion stack
Implementation notes
- Rust stores each tree node as
Node { value: i32, left: Option<Box<Node>>, right: Option<Box<Node>> }, so child links own boxed subtrees andNonemarks an empty child. preorder(node: &Option<Box<Node>>, output: &mut Vec<i32>)borrows the tree and mutates only the output vector; recursive calls pass&n.leftand&n.rightrather than moving child boxes.if let Some(n) = nodeskipsNonechildren. For real nodes,n.valueis copied intooutputbefore the left and right recursive calls.- The checked source imports
VecDeque, but this traversal does not use a queue; the traversal state is the Rust call stack plusoutput: Vec<i32>. - The trace records visit-before-children states in this order:
4,2,1,3,6,5,7, with output growing from[]to[4, 2, 1, 3, 6, 5, 7]. list_string(&output)borrows the result slice, joins display-formatted integers, andprintln!("{}", ...)prints[4, 2, 1, 3, 6, 5, 7].