Problem
We have seen Implement stack using an array. In a previous solution, we implemented a stack using an array with a fixed capacity. However, this implementation has the limitation of overflow when the number of elements exceeds the array size. To overcome this limitation, we can implement a dynamically growing stack that increases its capacity when it reaches the maximum size.
Examples:
Example 1:
|
|
Solution
Method 1 - Growing the array
A stack follows the Last In First Out (LIFO) principle. By using an array to implement a dynamically growing stack, we can manage elements efficiently by resizing the array when necessary. This approach involves doubling the array size whenever it gets full, similar to how dynamic arrays (like Python lists or Java ArrayLists) work.
A fixed-size array is used in static array-based stack implementations, where the stack’s capacity is fixed at initialization. In contrast, a dynamic array-based implementation uses an array with an initial capacity that grows as needed. When the array reaches its capacity, a new array with double the current capacity is created, and elements from the old array are copied to the new one. This dynamic resizing ensures no overflow occurs.
Points to Consider for Implementing a Stack with Resizable Arrays
- Capacity:
- Define an initial capacity for the array, and double the array size when it reaches maximum capacity.
- Initialize the stack with a minimal capacity, such as 1, to simplify the implementation.
- No Overflow:
- Dynamic resizing prevents overflow by creating a new, larger array whenever needed.
- Waste of Space:
- As the stack size grows and frequently pops, unused space may accumulate.
- To optimize space, consider reducing the array size to a quarter of its current capacity when appropriate.
- Underflow:
- Occurs when no elements are left in the stack.
Key Operations
Initialization
- Begin by initializing an array
stack[]
with an initial capacity of 1. - Set the index
top
to -1, indicating an empty stack.
Push Operation
- If the stack is full (i.e., it has reached its maximum capacity):
- Resize the array to double its current capacity.
- Otherwise:
- Increment the
top
index by 1. - Insert the new value at
stack[top]
.
- Increment the
Pop Operation
- If the stack is empty:
- Throw an exception.
- Otherwise:
- Retrieve and store the element from
stack[top]
. - Decrement the
top
index by 1, effectively removing the element.
- Retrieve and store the element from
Optionally, we can shrink the array. Similar to push operation, can repeated halving work here? Answer is no.
Suppose the array size is almost full, so we double the array, and again due to some reason stack shrinked, and we shrinked the array by 2, and again only few elements are added such that stack again is full, and again we have to double. So, we have to do it again and again.
But if we shrink the array size by 4, then atleast we don’t have to worry again and again for array size.
Other Operations
- Top Operation:
- Return the element at the top index without removing it.
- isEmpty Operation:
- Check if the top index is -1, indicating the stack is empty.
Code
|
|
|
|
VS Linked list implemenation
Read more - Implement stack using linked list#Resizing array vs linked list.