Stack Implementation Using Array in DSA Rust - Time & Space Complexity
We want to understand how fast operations like push and pop run in a stack built with an array.
How does the time taken change as we add more items?
Analyze the time complexity of the following code snippet.
struct Stack {
data: Vec<i32>,
}
impl Stack {
fn push(&mut self, val: i32) {
self.data.push(val);
}
fn pop(&mut self) -> Option<i32> {
self.data.pop()
}
}
This code shows a stack using a Rust vector (array). Push adds an item to the end, pop removes the last item.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Adding or removing one element at the end of the array.
- How many times: Each push or pop runs once per call, no loops inside.
Each push or pop does a fixed amount of work, no matter how many items are in the stack.
| Input Size (n) | Approx. Operations per push/pop |
|---|---|
| 10 | 1 |
| 100 | 1 |
| 1000 | 1 |
Pattern observation: The time stays the same even as the stack grows larger.
Time Complexity: O(1)
This means each push or pop takes the same short time, no matter how many items are in the stack.
[X] Wrong: "Push or pop takes longer as the stack grows because the array is bigger."
[OK] Correct: The operations only add or remove at the end, so they do not need to look at all items.
Knowing that stack operations run in constant time shows you understand efficient data structures, a key skill in coding interviews.
"What if the stack was implemented using a linked list instead of an array? How would the time complexity change?"
Practice
Solution
Step 1: Understand stack behavior
A stack stores elements in last-in-first-out order, meaning the last element added is the first to be removed.Step 2: Role of array in stack
An array provides a fixed-size container to hold elements in order, supporting push and pop operations at one end.Final Answer:
To store elements in a fixed-size, last-in-first-out order -> Option BQuick Check:
Stack = LIFO with fixed size [OK]
- Confusing stack with queue (FIFO)
- Thinking array sorts elements automatically
- Assuming random access is main stack feature
Solution
Step 1: Identify fixed-size array syntax in Rust
Rust fixed-size arrays use syntax: let name: [type; size] = [initial_value; size];Step 2: Match options to syntax
let stack: [i32; 5] = [0; 5]; matches this exactly: let stack: [i32; 5] = [0; 5]; initializes 5 integers to zero.Final Answer:
let stack: [i32; 5] = [0; 5]; -> Option AQuick Check:
Fixed-size array syntax = let stack: [i32; 5] = [0; 5]; [OK]
- Using Vec instead of fixed-size array
- Incorrect array initialization syntax
- Confusing tuple syntax with array
let mut stack: [i32; 3] = [0; 3];
let mut top = -1;
// Push function
fn push(stack: &mut [i32; 3], top: &mut i32, value: i32) {
if *top < 2 {
*top += 1;
stack[*top as usize] = value;
}
}
push(&mut stack, &mut top, 10);
push(&mut stack, &mut top, 20);
println!("{:?}", stack);Solution
Step 1: Trace push calls and stack changes
Initially, stack = [0, 0, 0], top = -1. First push: top becomes 0, stack[0] = 10 -> [10, 0, 0]. Second push: top becomes 1, stack[1] = 20 -> [10, 20, 0].Step 2: Print final stack state
Printing stack shows [10, 20, 0].Final Answer:
[10, 20, 0] -> Option CQuick Check:
Push adds at top index, stack = [10, 20, 0] [OK]
- Not updating top index before assignment
- Confusing array indices order
- Assuming push adds at end regardless of top
fn pop(stack: &[i32; 3], top: &mut i32) -> Option<i32> {
if *top >= 0 {
let val = stack[*top as usize];
*top -= 1;
Some(val)
} else {
None
}
}Solution
Step 1: Analyze the pop function code
The function takes an immutable reference to the stack (&[i32; 3]) and a mutable reference to top. It only reads from the stack at index *top and decrements top.Step 2: Verify compilation and logic
No writes to the stack array occur, so an immutable reference is sufficient and correct. The function handles empty stack with None and returns the popped value properly.Final Answer:
No error, function is correct -> Option DQuick Check:
Immutable stack reference OK for read-only access in pop [OK]
- Assuming stack must be mutable for pop operations
- Suggesting unnecessary global variables
- Incorrectly changing return type from Option<i32>
let mut stack: [i32; 4] = [0; 4];
let mut top = -1;
// Push function
fn push(stack: &mut [i32; 4], top: &mut i32, value: i32) {
if *top < 3 {
*top += 1;
stack[*top as usize] = value;
} else {
println!("Stack Overflow");
}
}
// Operations:
push(&mut stack, &mut top, 5);
push(&mut stack, &mut top, 10);
push(&mut stack, &mut top, 15);
push(&mut stack, &mut top, 20);
push(&mut stack, &mut top, 25);Solution
Step 1: Understand stack size and top limit
Stack size is 4, so top can go from -1 to 3 (indices 0 to 3).Step 2: Trace push calls and top value
Push 5: top=0 Push 10: top=1 Push 15: top=2 Push 20: top=3 Push 25: top=3 already, so condition *top < 3 fails, triggers overflow.Final Answer:
The last push call with value 25 causes overflow -> Option AQuick Check:
Stack size 4, 5th push overflows [OK]
- Counting top starting at 0 instead of -1
- Assuming overflow at fewer pushes
- Ignoring condition check in push
Ready to prove it?
Pass the test and this pattern moves unknown
