Expression evaluation in Rust - Time & Space Complexity
When we evaluate expressions in code, we want to know how the time it takes grows as the expression gets bigger.
We ask: How does the number of steps change when the expression has more parts?
Analyze the time complexity of the following code snippet.
fn evaluate_expression(expr: &str) -> i32 {
let mut stack = Vec::new();
for ch in expr.chars() {
if ch.is_digit(10) {
stack.push(ch.to_digit(10).unwrap() as i32);
} else {
let b = stack.pop().unwrap();
let a = stack.pop().unwrap();
let res = match ch {
'+' => a + b,
'-' => a - b,
'*' => a * b,
'/' => a / b,
_ => 0,
};
stack.push(res);
}
}
stack.pop().unwrap()
}
This code evaluates a simple expression in postfix form using a stack.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Looping through each character in the expression string.
- How many times: Once for every character in the input expression.
As the expression gets longer, the code checks each character once, so the work grows steadily.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps |
| 100 | About 100 steps |
| 1000 | About 1000 steps |
Pattern observation: The number of steps grows directly with the size of the expression.
Time Complexity: O(n)
This means the time to evaluate grows in a straight line with the length of the expression.
[X] Wrong: "Evaluating an expression always takes a lot more time because of nested operations."
[OK] Correct: Here, each character is handled once in order, so nested or not, the time grows just with expression length.
Understanding how expression evaluation scales helps you explain how code handles bigger inputs clearly and confidently.
"What if we changed the input to include parentheses and had to handle them? How would the time complexity change?"
Practice
let result = 5 + 3 * 2;Choose the correct description.
Solution
Step 1: Understand operator precedence in Rust
Multiplication (*) has higher precedence than addition (+), so 3 * 2 is calculated first.Step 2: Calculate the expression step-by-step
3 * 2 = 6, then 5 + 6 = 11.Final Answer:
Calculates 3 times 2, then adds 5 -> Option AQuick Check:
5 + (3 * 2) = 11 [OK]
- Adding numbers left to right ignoring precedence
- Multiplying after addition
- Confusing operator precedence
4 + 7 to a variable named sum in Rust?Solution
Step 1: Recall Rust variable assignment syntax
In Rust, uselet variable = expression;to assign a value.Step 2: Check each option for correct syntax
let sum = 4 + 7; uses correct syntax:let sum = 4 + 7;. Others have syntax errors.Final Answer:
let sum = 4 + 7; -> Option CQuick Check:
Correct Rust assignment syntax [OK]
- Using '==' instead of '=' for assignment
- Placing 'let' after variable name
- Using ':' instead of '=' for assignment
fn main() {
let x = 10;
let y = 3;
let result = x / y + x % y;
println!("{}", result);
}Solution
Step 1: Calculate integer division and remainder
10 / 3 = 3 (integer division), 10 % 3 = 1 (remainder).Step 2: Add the results
3 + 1 = 4.Final Answer:
4 -> Option DQuick Check:
10 / 3 + 10 % 3 = 4 [OK]
- Treating division as float division
- Confusing remainder with division result
- Adding operands incorrectly
fn main() {
let a = 5;
let b = 0;
let c = a / b;
println!("{}", c);
}Solution
Step 1: Analyze the division operation
The code divides 'a' by 'b', where 'b' is zero.Step 2: Understand Rust runtime behavior
Dividing by zero in Rust causes a runtime panic (crash), not a compile error.Final Answer:
Division by zero causes a runtime panic -> Option AQuick Check:
Division by zero panics in Rust [OK]
- Thinking division by zero is a compile error
- Ignoring runtime panics
- Assuming variable declaration errors
let numbers = [1, 2, 3, 4, 5, 6];
let sum_even = /* fill here */;
println!("{}", sum_even);Choose the correct expression to replace
/* fill here */.Solution
Step 1: Understand the goal
We want to sum only even numbers from the list.Step 2: Analyze each option
numbers.iter().filter(|&&x| x % 2 == 0).sum::<i32>() filters even numbers (x % 2 == 0) and sums them. numbers.iter().map(|x| x * 2).sum::<i32>() doubles all numbers then sums (wrong). numbers.iter().filter(|&x| x % 2 != 0).sum::<i32>() sums odd numbers (wrong). numbers.iter().sum::<i32>() sums all numbers (wrong).Final Answer:
numbers.iter().filter(|&&x| x % 2 == 0).sum::<i32>() -> Option BQuick Check:
Filter evens then sum [OK]
- Summing all numbers without filtering
- Filtering odd numbers instead of even
- Mapping values incorrectly before sum
Ready to prove it?
Pass the test and this pattern moves unknown
