Dynamic Stack Using Resizable Array in DSA C# - 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[] items = new int[2];
private int count = 0;
public void Push(int item)
{
if (count == items.Length)
Resize();
items[count++] = item;
}
private void Resize()
{
int[] newItems = new int[items.Length * 2];
for (int i = 0; i < items.Length; i++)
newItems[i] = items[i];
items = newItems;
}
}
This code adds items to a stack and doubles the array size when full.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Adding an item to the array (Push method).
- How many times: Usually once per Push, but sometimes triggers Resize.
- Resize operation: Copies all existing items to a new larger array.
- How many times Resize runs: Only when array is full, doubling size each time.
Most Push operations take a fixed small time. Occasionally, a Push causes Resize, which copies all items.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 simple adds + 14 copies during resizes |
| 100 | About 100 simple adds + 126 copies during resizes |
| 1000 | About 1000 simple adds + 1022 copies during resizes |
Pattern observation: Most operations are quick, but resizing cost grows with number of items copied.
Time Complexity: O(1) amortized
This means each Push usually takes constant time, but sometimes takes longer when resizing, averaged out over many operations.
[X] Wrong: "Every Push takes a long time because of resizing."
[OK] Correct: Resizing happens rarely and its cost spreads out over many Pushes, so most Pushes are fast.
Understanding amortized time helps you explain why dynamic arrays and stacks are efficient in real use, a key skill in interviews.
"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 set capacity and cannot grow beyond it, causing overflow if exceeded.Step 2: Understand dynamic stack advantage
A dynamic stack resizes its array automatically when full, allowing more elements without overflow.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 uses less memory always
- Believing dynamic stack has fixed capacity
- Confusing dynamic stack with linked list stack
Solution
Step 1: Understand array resizing in C#
Arrays in C# have fixed length; to resize, use Array.Resize(ref array, newSize) which copies old elements.Step 2: Analyze options
Array.Resize(ref array, array.Length * 2); uses Array.Resize correctly. array = new int[array.Length * 2]; creates a new array but loses old data. array.Length = array.Length * 2; is invalid syntax. array = array.Concat(array).ToArray(); uses LINQ but is inefficient and not typical for stack resizing.Final Answer:
Array.Resize(ref array, array.Length * 2); -> Option DQuick Check:
Array.Resize method resizes arrays properly [OK]
- Trying to set array.Length directly
- Creating new array without copying old data
- Using LINQ Concat for resizing inefficiently
DynamicStack stack = new DynamicStack(); stack.Push(10); stack.Push(20); stack.Push(30); stack.Pop(); stack.Push(40); stack.PrintStack();
What will be the printed output?
Solution
Step 1: Trace stack operations
Push 10, stack: 10
Push 20, stack: 20 -> 10
Push 30, stack: 30 -> 20 -> 10
Pop removes 30, stack: 20 -> 10
Push 40, stack: 40 -> 20 -> 10Step 2: Determine printed output
PrintStack prints from top to bottom ending with null: 40 -> 20 -> 10 -> nullFinal Answer:
40 -> 20 -> 10 -> null -> Option BQuick Check:
Stack top after operations = 40 [OK]
- Forgetting pop removes top element
- Printing stack in wrong order
- Including popped elements in output
public void Push(int item) {
if (top == array.Length) {
Array.Resize(ref array, array.Length * 2);
}
array[top] = item;
top++;
}Solution
Step 1: Analyze resizing condition
top equals array.Length means array is full, so resizing is needed before adding new item.Step 2: Check push logic
Assign item at array[top], then increment top. This correctly places item and moves top pointer.Final Answer:
No bug; the code resizes and pushes correctly. -> Option AQuick Check:
Resize when full, assign then increment top [OK]
- Using wrong resize condition (off by one)
- Incrementing top before assignment
- Assuming top starts at 1 instead of 0
Solution
Step 1: Understand shrinking condition
To save memory, shrink when usage is low: top ≤ 1/4 capacity triggers halving the array size.Step 2: Apply resizing correctly
Use Array.Resize(ref array, array.Length / 2) to shrink safely after popping, preserving existing elements.Final Answer:
After popping, check if top <= array.Length / 4, then resize array to array.Length / 2 using Array.Resize(ref array, newSize). -> Option CQuick Check:
Shrink when quarter full using Array.Resize [OK]
- Shrinking too often causing overhead
- Shrinking to quarter size instead of half
- Not preserving data during resize
Ready to prove it?
Pass the test and this pattern moves unknown
