Count Total Nodes in Binary Tree in DSA Rust - Time & Space Complexity
We want to know how long it takes to count all nodes in a binary tree.
How does the time grow as the tree gets bigger?
Analyze the time complexity of the following code snippet.
fn count_nodes(root: &Option>) -> usize {
match root {
None => 0,
Some(node) => 1 + count_nodes(&node.left) + count_nodes(&node.right),
}
}
struct TreeNode {
left: Option>,
right: Option>,
}
This code counts all nodes by visiting each node once in the binary tree.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive call visiting each node once.
- How many times: Once per node in the tree.
Each node is visited exactly one time, so the work grows directly with the number of nodes.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 visits |
| 100 | About 100 visits |
| 1000 | About 1000 visits |
Pattern observation: The time grows linearly as the tree size increases.
Time Complexity: O(n)
This means the time to count nodes grows directly with the number of nodes in the tree.
[X] Wrong: "The function only visits some nodes, so it runs faster than O(n)."
[OK] Correct: The recursion visits every node exactly once, so it must look at all nodes to count them.
Counting nodes in a tree is a basic skill that shows you understand recursion and tree traversal.
"What if we changed the tree to be a balanced binary search tree? How would the time complexity change?"
Practice
Solution
Step 1: Understand the function's purpose
The function is designed to count how many nodes exist in the entire binary tree.Step 2: Differentiate from other tree properties
Counting nodes is different from calculating height, sum of values, or counting leaves.Final Answer:
It returns the total number of nodes in the tree. -> Option BQuick Check:
Counting nodes = total nodes [OK]
- Confusing node count with tree height
- Counting only leaf nodes
- Summing node values instead of counting
Solution
Step 1: Understand Rust ownership and recursive types
Recursive types like binary trees require using Box and Option to allow nullable pointers and heap allocation.Step 2: Identify correct struct syntax
Option allows left and right to be either None or Some(Box<Node>), which is correct for binary trees.Final Answer:
struct Node { value: i32, left: Option, right: Option } -> Option AQuick Check:
Use Option for nullable children [OK]
- Using direct Node type causing infinite size error
- Using references without lifetimes
- Not wrapping children in Option
fn count_nodes(root: &Option) -> i32 {
match root {
None => 0,
Some(node) => 1 + count_nodes(&node.left) + count_nodes(&node.right),
}
}
// Tree structure:
// 10
// / \
// 5 15
// /
// 12
let root = Some(Box::new(Node {
value: 10,
left: Some(Box::new(Node { value: 5, left: None, right: None })),
right: Some(Box::new(Node {
value: 15,
left: Some(Box::new(Node { value: 12, left: None, right: None })),
right: None,
})),
}));
println!("{}", count_nodes(&root));Solution
Step 1: Count nodes in each subtree
Root node (10) counts as 1. Left subtree has 1 node (5). Right subtree has 2 nodes (15 and 12).Step 2: Sum all nodes
Total nodes = 1 (root) + 1 (left) + 2 (right) = 4.Final Answer:
4 -> Option DQuick Check:
1 + 1 + 2 = 4 [OK]
- Counting only leaf nodes
- Forgetting to add root node
- Miscounting subtree nodes
fn count_nodes(root: Option) -> i32 {
if root.is_none() {
return 0;
}
1 + count_nodes(root.unwrap().left) + count_nodes(root.unwrap().right)
}Solution
Step 1: Understand ownership and unwrap behavior
Calling unwrap() consumes the Option, so calling it twice on the same variable causes a move error.Step 2: Identify correct fix
Store the result of unwrap() in a variable to avoid multiple moves or use references.Final Answer:
Using unwrap() twice consumes the value causing a move error. -> Option AQuick Check:
unwrap() moves value; multiple calls cause error [OK]
- Calling unwrap() multiple times on same Option
- Ignoring ownership and move semantics
- Returning wrong base case value
Solution
Step 1: Traverse entire tree recursively
We must visit every node to check its value and count accordingly.Step 2: Count nodes with value > 10 correctly
If node's value is greater than 10, add 1 plus counts from left and right subtrees; else add only counts from children.Final Answer:
Function that adds 1 only if node.value > 10, else sums children counts. -> Option CQuick Check:
Count nodes with value > 10 recursively [OK]
- Counting all nodes regardless of value
- Returning 0 when node value <= 10 without counting children
- Not traversing entire tree
Ready to prove it?
Pass the test and this pattern moves unknown
