Boundary Traversal of Binary Tree in DSA Rust - Time & Space Complexity
We want to understand how the time needed to do a boundary traversal of a binary tree changes as the tree grows.
Specifically, how does the number of nodes affect the work done?
Analyze the time complexity of the following code snippet.
fn boundary_traversal(root: &Option>) -> Vec {
let mut result = Vec::new();
if root.is_none() { return result; }
let root_ref = root.as_ref().unwrap();
result.push(root_ref.val);
fn left_boundary(node: &Option>, res: &mut Vec) {
if let Some(n) = node {
if n.left.is_some() {
res.push(n.val);
left_boundary(&n.left, res);
} else if n.right.is_some() {
res.push(n.val);
left_boundary(&n.right, res);
}
}
}
// Similar functions for leaves and right boundary omitted for brevity
left_boundary(&root_ref.left, &mut result);
// leaves(&root_ref, &mut result);
// right_boundary(&root_ref.right, &mut result);
result
}
This code collects the boundary nodes of a binary tree by traversing the left edge, leaves, and right edge.
- Primary operation: Recursive traversal of nodes to collect boundary nodes.
- How many times: Each node is visited at most once during the traversal.
As the number of nodes grows, the traversal visits each node once, so the work grows directly with the number of nodes.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 node visits |
| 100 | About 100 node visits |
| 1000 | About 1000 node visits |
Pattern observation: The number of operations grows linearly with the number of nodes.
Time Complexity: O(n)
This means the time to do the boundary traversal grows in direct proportion to the number of nodes in the tree.
[X] Wrong: "Boundary traversal only visits a few nodes, so it is faster than visiting all nodes."
[OK] Correct: The traversal must check all nodes to find leaves and edges, so it still visits every node once.
Understanding how tree traversals scale helps you explain your approach clearly and shows you know how to analyze algorithms.
"What if the tree is skewed (all nodes only have one child)? How would the time complexity change?"
Practice
Boundary Traversal of Binary Tree?Solution
Step 1: Understand boundary traversal definition
Boundary traversal prints nodes on the edges of the tree: left boundary, leaves, and right boundary.Step 2: Identify traversal direction
The traversal is done in anti-clockwise order starting from root, left boundary, leaves, then right boundary.Final Answer:
To print all nodes on the boundary in anti-clockwise direction -> Option DQuick Check:
Boundary traversal = anti-clockwise boundary nodes [OK]
- Confusing boundary traversal with level order traversal
- Including internal nodes not on boundary
- Printing right boundary in clockwise order
struct Node { val: i32, left: Option, right: Option }?Solution
Step 1: Analyze ownership and borrowing in Rust
Binary tree nodes are wrapped inOptionto allow null and heap allocation. Passing by reference avoids ownership transfer.Step 2: Match function signature with correct parameter type
Using&Optionallows borrowing the root node safely without moving ownership.Final Answer:
fn boundary_traversal(root: &Option) -> Vec<i32> -> Option BQuick Check:
Borrow Option for traversal [OK]
- Passing Node by value causes ownership move
- Using Option<Node> instead of Option
- Using &Node without Option wrapper
fn main() {
let root = Some(Box::new(Node {
val: 1,
left: Some(Box::new(Node {
val: 2,
left: Some(Box::new(Node { val: 4, left: None, right: None })),
right: Some(Box::new(Node {
val: 5,
left: Some(Box::new(Node { val: 7, left: None, right: None })),
right: Some(Box::new(Node { val: 8, left: None, right: None })),
})),
})),
right: Some(Box::new(Node {
val: 3,
left: None,
right: Some(Box::new(Node {
val: 6,
left: Some(Box::new(Node { val: 9, left: None, right: None })),
right: None,
})),
})),
}));
let result = boundary_traversal(&root);
println!("{:?}", result);
}Solution
Step 1: Identify boundary nodes in anti-clockwise order
Root: 1; Left boundary (excluding leaves): 2; Leaves (left-to-right): 4, 7, 8, 9; Right boundary (excluding leaves, bottom-up): 6, 3.Step 2: Combine nodes without duplicates
Boundary traversal = [1, 2, 4, 7, 8, 9, 6, 3]Final Answer:
[1, 2, 4, 7, 8, 9, 6, 3] -> Option AQuick Check:
Boundary nodes = [1,2,4,7,8,9,6,3] [OK]
- Including internal nodes like 5 in boundary
- Adding right boundary top-down instead of bottom-up
- Missing leaf nodes on right subtree
fn print_left_boundary(node: &Option) {
if let Some(n) = node {
if n.left.is_some() {
println!("{}", n.val);
print_left_boundary(&n.left);
} else if n.right.is_some() {
println!("{}", n.val);
print_left_boundary(&n.right);
}
}
}Solution
Step 1: Analyze recursion logic
The function recurses on the left child if present, but falls back to recursing on the right child if no left child. For left boundary, always prefer and recurse only on left child (stop if absent).Step 2: Understand boundary traversal rule for left boundary
This incorrect fallback includes right subtree nodes in the left boundary traversal.Final Answer:
It incorrectly recurses on the right child when the left child is absent -> Option AQuick Check:
Left boundary: recurse left only [OK]
- Recursing on right child when left is absent in left boundary
- Not handling None nodes properly
- Incorrectly printing leaves in left boundary
Solution
Step 1: Understand clockwise boundary traversal order
Clockwise traversal starts at root, then right boundary top-down, leaves from right to left, then left boundary bottom-up.Step 2: Match the option with correct order
Print root, then right boundary top-down, leaves right to left, then left boundary bottom-up matches this order exactly, ensuring correct clockwise traversal.Final Answer:
Print root, then right boundary top-down, leaves right to left, then left boundary bottom-up -> Option CQuick Check:
Clockwise boundary = root + right + leaves + left reversed [OK]
- Using anti-clockwise order for clockwise traversal
- Printing leaves left to right instead of right to left
- Reversing boundaries incorrectly
Ready to prove it?
Pass the test and this pattern moves unknown
