BST Insert Operation in DSA Rust - Time & Space Complexity
We want to understand how the time to insert a value in a Binary Search Tree changes as the tree grows.
How does the number of steps needed to insert a new value grow with the size of the tree?
Analyze the time complexity of the following code snippet.
struct Node {
value: i32,
left: Option>,
right: Option>,
}
fn insert(root: &mut Option>, val: i32) {
match root {
None => *root = Some(Box::new(Node { value: val, left: None, right: None })),
Some(node) => {
if val < node.value {
insert(&mut node.left, val);
} else {
insert(&mut node.right, val);
}
}
}
}
This code inserts a value into a Binary Search Tree by moving left or right until it finds the right spot.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive calls moving down the tree nodes.
- How many times: At most once per tree level, until a leaf spot is found.
Each insert moves down one level in the tree, so the steps grow with the tree's height.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | Up to 4 steps (if tree is balanced) |
| 100 | Up to 7 steps (if tree is balanced) |
| 1000 | Up to 10 steps (if tree is balanced) |
Pattern observation: In a balanced tree, steps grow slowly (logarithmically) as the tree grows.
Time Complexity: O(h) where h is the tree height
This means the time to insert depends on how tall the tree is, not just how many nodes it has.
[X] Wrong: "Insertion always takes the same time regardless of tree shape."
[OK] Correct: If the tree is unbalanced and looks like a linked list, insertion can take much longer because you must go through many nodes.
Understanding how tree shape affects insert time helps you explain trade-offs and choose the right data structure in real problems.
"What if we kept the tree balanced after each insert? How would the time complexity change?"
Practice
insert operation in a Binary Search Tree (BST)?Solution
Step 1: Understand BST property
A BST keeps values in order: left child less, right child greater than parent.Step 2: Purpose of insert
Insert adds a new value so the tree remains ordered by BST rules.Final Answer:
To add a new value while keeping the BST property intact -> Option AQuick Check:
Insert = Add value maintaining order [OK]
- Confusing insert with delete operation
- Thinking insert balances the tree automatically
- Believing insert finds max value
Solution
Step 1: Understand ownership in Rust BST insert
Insert usually takes ownership of the node (Box<Node>) and returns updated Box<Node>.Step 2: Match signature to ownership pattern
fn insert(self: Box<Node>, val: i32) -> Box<Node> matches: takes self as Box<Node>, returns Box<Node>. Others mismatch ownership or mutability.Final Answer:
fn insert(self: Box<Node>, val: i32) -> Box<Node> -> Option CQuick Check:
Ownership insert = self Box<Node> in, Box<Node> out [OK]
- Using &self instead of self for ownership
- Returning reference instead of Box<Node>
- Missing self parameter
Solution
Step 1: Insert values in BST order
Insert 10 as root, 5 left of 10, 15 right of 10, 7 right of 5.Step 2: Perform in-order traversal
In-order visits left, root, right: 5, 7, 10, 15.Final Answer:
[5, 7, 10, 15] -> Option BQuick Check:
In-order = sorted values [OK]
- Confusing pre-order with in-order traversal
- Placing 7 as left child of 5 incorrectly
- Listing values in insertion order
fn insert(mut root: Option, val: i32) -> Option {
if root.is_none() {
return Some(Box::new(Node::new(val)));
}
if val < root.as_ref().unwrap().val {
root.as_mut().unwrap().left = insert(root.as_mut().unwrap().left.take(), val);
} else {
root.as_mut().unwrap().right = insert(root.as_mut().unwrap().right.take(), val);
}
Some(root.unwrap())
}
What is the bug in this code?Solution
Step 1: Analyze unwrap() usage at function end
root.unwrap() consumes root, but root is borrowed mutably earlier, causing move error.Step 2: Correct approach for returning root
Return root directly as Some(root) without unwrap to avoid move.Final Answer:
Calling unwrap() on root at the end consumes it, causing a move error -> Option AQuick Check:
unwrap() consumes Option, causes move error [OK]
- Ignoring move semantics of unwrap()
- Thinking take() is incorrect here
- Assuming missing return in else branch
Solution
Step 1: Insert values step-by-step
Insert 20 as root; 10 left of 20; 30 right of 20; 25 left of 30; 35 right of 30; 5 left of 10.Step 2: Perform pre-order traversal
Pre-order visits root, left subtree, right subtree: 20, 10, 5, 30, 25, 35.Final Answer:
[20, 10, 5, 30, 25, 35] -> Option DQuick Check:
Pre-order = root-left-right [OK]
- Confusing pre-order with in-order traversal
- Inserting nodes in wrong positions
- Listing sorted values instead of traversal order
Ready to prove it?
Pass the test and this pattern moves unknown
