Dynamic Stack Using Resizable Array in DSA Java - Time & Space Complexity
We want to understand how the time to add or remove items from a dynamic stack changes as the stack grows.
How does resizing the array affect the speed of stack operations?
Analyze the time complexity of the following code snippet.
public class DynamicStack {
private int[] arr = new int[2];
private int size = 0;
public void push(int val) {
if (size == arr.length) {
resize();
}
arr[size++] = val;
}
private void resize() {
int[] newArr = new int[arr.length * 2];
for (int i = 0; i < arr.length; i++) {
newArr[i] = arr[i];
}
arr = newArr;
}
}
This code adds items to a stack and doubles the array size when full.
Look for loops or repeated steps that take time.
- Primary operation: Adding an item (push) to the stack.
- How many times: Each push usually takes one step, but sometimes triggers resizing which copies all items.
- Resizing loop: Copies all current items to a new bigger array.
Most pushes take constant time, but resizing happens less often as the stack grows.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 simple pushes + 3 resizes copying items |
| 100 | About 100 simple pushes + 7 resizes copying items |
| 1000 | About 1000 simple pushes + 10 resizes copying items |
Pattern observation: Resizing happens rarely and copying cost spreads out, so average time per push stays low.
Time Complexity: O(1) amortized
This means each push usually takes a quick step, and resizing cost is spread out so average time stays constant.
[X] Wrong: "Every push takes a long time because of resizing."
[OK] Correct: Resizing happens only occasionally, so most pushes are fast and the average time is low.
Understanding amortized time helps you explain why dynamic arrays and stacks are efficient in real programs.
"What if we increased the array size by only 1 each time instead of doubling? How would the time complexity change?"
Practice
Solution
Step 1: Understand fixed-size array stack limitation
A fixed-size array stack has a maximum capacity that cannot change, so it can overflow if too many elements are pushed.Step 2: Understand dynamic stack resizing
A dynamic stack using a resizable array can increase or decrease its size automatically when needed, avoiding overflow and wasting less memory.Final Answer:
It can grow or shrink automatically as elements are pushed or popped. -> Option AQuick Check:
Dynamic resizing = automatic growth/shrink [OK]
- Thinking dynamic stack never resizes
- Confusing dynamic stack with linked list stack
- Assuming fixed size means dynamic resizing
Solution
Step 1: Check condition for resizing
The array should resize when the stack is full, i.e., when top equals array length.Step 2: Check resizing operation
The array size should double to accommodate more elements, so new size is arr.length * 2.Final Answer:
if (top == arr.length) { arr = Arrays.copyOf(arr, arr.length * 2); } -> Option AQuick Check:
Resize when full, double size [OK]
- Resizing when top > length (impossible)
- Shrinking array instead of doubling
- Resizing when array not full
DynamicStack stack = new DynamicStack(); stack.push(10); stack.push(20); stack.push(30); stack.pop(); stack.push(40); stack.push(50); System.out.println(stack);
What will be the printed output if the stack's toString method prints elements from bottom to top separated by ' -> ' and ends with ' -> null'?
Solution
Step 1: Trace push and pop operations
Push 10, 20, 30: stack = [10, 20, 30]
Pop removes 30: stack = [10, 20]
Push 40, 50: stack = [10, 20, 40, 50]Step 2: Understand toString output
Prints from bottom to top separated by ' -> ' ending with ' -> null'. So output is "10 -> 20 -> 40 -> 50 -> null".Final Answer:
10 -> 20 -> 40 -> 50 -> null -> Option DQuick Check:
Stack after operations = 10,20,40,50 [OK]
- Forgetting pop removes last pushed element
- Printing top to bottom instead of bottom to top
- Including popped element in output
public int pop() {
if (top == 0) throw new EmptyStackException();
int val = arr[--top];
if (top < arr.length / 4) {
arr = Arrays.copyOf(arr, arr.length / 2);
}
return val;
}Solution
Step 1: Analyze shrinking condition and operation
The array shrinks when top < arr.length / 4 by halving the array size.Step 2: Identify potential bug
If array size is small (like 1 or 2), halving repeatedly can reduce array size to zero, causing errors on next push/pop.Final Answer:
Shrinking array without checking minimum size can cause array size zero. -> Option BQuick Check:
Check minimum array size before shrinking [OK]
- Not checking for empty stack before pop
- Wrong condition for shrinking
- Shrinking array too small causing errors
public int pop() {
if (top == 0) throw new EmptyStackException();
int val = arr[--top];
if (top < arr.length / 4 && arr.length > 4) {
arr = Arrays.copyOf(arr, Math.max(arr.length / 2, 4));
}
return val;
}Solution
Step 1: Check shrinking condition and minimum size
The code shrinks array only if top < arr.length / 4 and arr.length > 4, ensuring minimum size 4.Step 2: Verify shrinking operation
Uses Math.max(arr.length / 2, 4) to avoid shrinking below 4, preventing errors.Final Answer:
Correctly shrinks array but never below size 4. -> Option CQuick Check:
Shrink with minimum size check = correct pop method [OK]
- Shrinking array below minimum size
- Not shrinking array when needed
- Incorrect condition for shrinking
Ready to prove it?
Pass the test and this pattern moves unknown
