Understand Stack and Their Implementation Using Array [06]
Learn the basics of stack data structures and how to implement them using arrays. This guide covers key operations like push, pop, peek, and more, with simple explanations and C++ code examples.
Wed, Dec 25, 2024
10 min read
Table of Contents
Congratulations!
You've thoroughly explored this topic!
Table of Contents
Congratulations!
You've thoroughly explored this topic!
1. Introduction
A stack
is a fundamental data structure in computer science, essential for managing and organizing data in a specific order. The stack follows a Last In, First Out (LIFO) principle, meaning that the last element added to the stack is the first one to be removed. This behavior is similar to a stack of plates, where the last plate placed on top is the first one to be taken off.
1. Key Characteristics of a Stack:
- LIFO (Last In, First Out): The last element added is always the first one to be removed.
- Push and Pop Operations: Elements are added to (push) or removed from (pop) the top of the stack.
- Limited Access: Only the top element is accessible for viewing or modification, not the other elements beneath it.
2. Visualizing a Stack:
Imagine a stack of books. When you add a new book, it goes on top of the stack. If you want to remove a book, you have to take the top one. The same rule applies in programming with stacks.
3. Applications of Stacks:
Stacks are used in a variety of computer science problems. Here are a few examples:
- Undo/Redo Functionality: Stacks are used to keep track of changes in applications, enabling users to undo or redo actions.
- Expression Evaluation: In mathematics and programming, stacks are used to evaluate expressions like postfix or infix.
- Function Call Management: When functions are called, the system pushes them onto the call stack, and once the function finishes, it is popped off.
2. Stack Operations
Stacks support a few essential operations that allow efficient management of the data. These operations are designed to work according to the LIFO (Last In, First Out) principle.
1. Push: Adding an Element to the Stack
The Push operation adds an element to the top of the stack. If there’s space in the stack (in case of a fixed-size stack), the new element is inserted on top of the current top element.
Pseudocode:
text1.Push(stack, element):2.if stack is not full:3.increment top index4.stack[top] = element5.else:6.print "Stack Overflow"
2. Pop: Removing the Top Element
The Pop operation removes the top element from the stack and returns it. After removal, the top pointer is decremented to point to the next element in the stack.
Pseudocode:
text1.Pop(stack):2.if stack is not empty:3.element = stack[top]4.decrement top index5.return element6.else:7.print "Stack Underflow"
3. Peek/Top: Viewing the Top Element
The Peek or Top operation allows you to view the top element of the stack without removing it. This is useful when you want to see what the current top element is but do not want to modify the stack.
Pseudocode:
text1.Peek(stack):2.if stack is not empty:3.return stack[top]4.else:5.print "Stack is Empty"
4. isEmpty: Checking if the Stack is Empty
The isEmpty operation checks whether the stack is empty. If the top index is -1 (or an equivalent value depending on the implementation), the stack is considered empty.
Pseudocode:
text1.isEmpty(stack):2.if top == -1:3.return true4.else:5.return false
5. isFull: Checking if the Stack is Full
The isFull operation checks if the stack has reached its maximum capacity. This is particularly relevant in stack implementations using arrays, where a fixed-size array is used to hold elements.
Pseudocode:
text1.isFull(stack):2.if top == maxSize - 1:3.return true4.else:5.return false
These operations form the core functionality of a stack and are crucial for its proper management and utilization in various algorithms and data structures.
3. Advantages and Limitations of Stacks
1. Advantages:
- Simple Data Management: Efficient LIFO structure, with fast operations like push, pop, and peek.
- Memory Efficiency: Low overhead, using memory proportional to the number of elements.
- Versatile Use Cases: Essential in function call management, undo/redo, expression parsing, and data reversal.
- Easy to Implement: Simple to implement with arrays or linked lists, with O(1) time complexity for main operations.
2. Limitations:
- Fixed Size (Array Implementation): Limited capacity, leading to stack overflow if full.
- Limited Element Access: Can only access the top element, requiring pops to access deeper elements.
- Memory Wastage: Fixed-size stacks may waste memory if not fully utilized.
- Limited to LIFO: Not ideal for tasks requiring other access patterns (e.g., FIFO).
4. Implementing a Stack Using Arrays
Here’s a full implementation of a stack using arrays in C++.
1. Define the Stack Class
We start by defining the stack class and initializing it with a maximum size of 3 for the stack.
cpp1.#include <iostream>2.using namespace std;3.4.#define MAX_SIZE 3 // Limiting the stack size to 3 for simplicity5.6.class Stack {7.private:8.int stack[MAX_SIZE]; // Array to store stack elements9.int top; // Index of the top element10.11.public:12.// Constructor to initialize the stack13.Stack() {14.top = -1; // Initialize the top index to -1 (indicating the stack is empty)15.}16.};
2. Code for the Push Operation
Next, we define the push
function that adds an element to the stack. If the stack is full, it prints a "Stack Overflow" message.
cpp1.// Push operation: Adds an element to the stack2.void push(int element) {3.if (top < MAX_SIZE - 1) {4.top++;5.stack[top] = element;6.cout << "Pushed " << element << " to stack." << endl;7.} else {8.cout << "Stack Overflow" << endl;9.}10.}
3. Code for the Pop Operation
The pop
function removes the top element from the stack. If the stack is empty, it prints a "Stack Underflow" message.
cpp1.// Pop operation: Removes the top element from the stack2.int pop() {3.if (top != -1) {4.int element = stack[top];5.top--;6.return element;7.} else {8.cout << "Stack Underflow" << endl;9.return -1; // Return a sentinel value indicating underflow10.}11.}
4. Code for the Peek Operation
The peek
function returns the top element without removing it from the stack. If the stack is empty, it prints "Stack is Empty".
cpp1.// Peek operation: Views the top element without removing it2.int peek() {3.if (top != -1) {4.return stack[top];5.} else {6.cout << "Stack is Empty" << endl;7.return -1; // Return a sentinel value indicating empty stack8.}9.}
5. Code for the isEmpty Operation
The isEmpty
function checks whether the stack is empty by verifying if top
is -1.
cpp1.// isEmpty operation: Checks if the stack is empty2.bool isEmpty() {3.return top == -1;4.}
6. Code for the isFull Operation
The isFull
function checks whether the stack has reached its maximum size.
cpp1.// isFull operation: Checks if the stack is full2.bool isFull() {3.return top == MAX_SIZE - 1;4.}
7. Full Code Implementation
Now, let's combine all the functions together and provide the complete implementation. We'll use a stack with a maximum size of 3 and demonstrate all operations.
cpp1.#include <iostream>2.using namespace std;3.4.#define MAX_SIZE 3 // Limiting the stack size to 3 for simplicity5.6.class Stack {7.private:8.int stack[MAX_SIZE]; // Array to store stack elements9.int top; // Index of the top element10.11.public:12.// Constructor to initialize the stack13.Stack() {14.top = -1; // Initialize the top index to -1 (indicating the stack is empty)15.}16.17.// Push operation: Adds an element to the stack18.void push(int element) {19.if (top < MAX_SIZE - 1) {20.top++;21.stack[top] = element;22.cout << "Pushed " << element << " to stack." << endl;23.} else {24.cout << "Stack Overflow" << endl;25.}26.}27.28.// Pop operation: Removes the top element from the stack29.int pop() {30.if (top != -1) {31.int element = stack[top];32.top--;33.return element;34.} else {35.cout << "Stack Underflow" << endl;36.return -1; // Return a sentinel value indicating underflow37.}38.}39.40.// Peek operation: Views the top element without removing it41.int peek() {42.if (top != -1) {43.return stack[top];44.} else {45.cout << "Stack is Empty" << endl;46.return -1; // Return a sentinel value indicating empty stack47.}48.}49.50.// isEmpty operation: Checks if the stack is empty51.bool isEmpty() {52.return top == -1;53.}54.55.// isFull operation: Checks if the stack is full56.bool isFull() {57.return top == MAX_SIZE - 1;58.}59.};60.61.int main() {62.Stack s;63.64.s.pop(); // Attempting to pop when the stack is empty65.66.// Pushing elements onto the stack67.s.push(10);68.s.push(20);69.s.push(30);70.71.// Attempting to push when the stack is full72.s.push(40); // This should trigger a stack overflow73.74.// Peeking the top element75.cout << "Top element is: " << s.peek() << endl;76.77.// Popping elements from the stack78.cout << "Popped element: " << s.pop() << endl;79.cout << "Popped element: " << s.pop() << endl;80.81.// Pushing more elements after popping82.s.push(40);83.s.push(50);84.85.// Final peek to show the current top element86.cout << "Top element is: " << s.peek() << endl;87.88.return 0;89.}
8. Example Walkthrough and Explanation:
-
Attempt to Pop When Empty:
s.pop()
→ Stack Underflow (since the stack is empty).
-
Push Operations:
s.push(10)
→ Stack: [10]s.push(20)
→ Stack: [10, 20]s.push(30)
→ Stack: [10, 20, 30]
-
Attempt to Push When Full:
s.push(40)
→ Stack Overflow (since the stack size is limited to 3).
-
Peek Operation:
peek()
→ Returns the top element (30), and prints "Top element is: 30".
-
Pop Operations:
pop()
→ Removes 30 (top element), now Stack: [10, 20].pop()
→ Removes 20 (next top element), now Stack: [10].
-
Push More Elements:
s.push(40)
→ Stack: [10, 40]s.push(50)
→ Stack: [10, 40, 50]
-
Final Peek:
peek()
→ Returns the top element (50), and prints "Top element is: 50".
5. Conclusion:
In this blog, we've explored the fundamentals of stacks, their key operations like push, pop, and peek, and how to implement a stack using arrays in C++. Understanding stacks is crucial as they are a fundamental data structure used in various algorithms and problem-solving tasks, such as function call management and expression evaluation. 📚
By mastering these basic concepts, you'll be well on your way to tackling more advanced topics in data structures and algorithms. Keep practicing, experimenting with different implementations, and stay curious—there’s always more to learn in the world of programming! 💡🚀
Happy coding! 🎉