1. What is a Stack? (LIFO Concept)
A Stack is a linear data structure that operates under the Last In, First Out (LIFO) principle. The last element placed on the stack is the first one to be removed.
Example 1: Stack Behavior Demonstration
#include <iostream>
#include <stack>
using namespace std;
int main() {
// Using C++ built-in stack to demonstrate LIFO
stack<int> s;
// Push elements
s.push(10);
s.push(20);
s.push(30);
cout << "Top element: " << s.top() << endl; // 30
// Pop elements (Last In, First Out)
cout << "Popping elements:" << endl;
while (!s.empty()) {
cout << s.top() << " ";
s.pop();
}
cout << endl; // 30 20 10
return 0;
}
Output:
Top element: 30
Popping elements:
30 20 10
LIFO Visualization:
Push 10 → Push 20 → Push 30 → Pop → Pop → Pop
↓ ↓ ↓
[10] [10] [10] [10] [] []
[20] [20] []
[30] Pop returns 30, then 20, then 10
2. Stack Implementation Using Array
A fixed-size array can be used to implement a stack where an integer top tracks the index of the top element.
Example 2: Complete Stack Class (Array-Based)
#include <iostream>
using namespace std;
const int MAX = 5; // Maximum size of the stack
class Stack {
private:
int arr[MAX]; // Array to store stack elements
int top; // Index of the top element
public:
// Constructor
Stack() {
top = -1; // Stack is initially empty
}
// Check if stack is full
bool isFull() {
return (top == MAX - 1);
}
// Check if stack is empty
bool isEmpty() {
return (top == -1);
}
// Push operation
void push(int value) {
if (isFull()) {
cout << "Stack Overflow! Cannot push " << value << endl;
} else {
top++;
arr[top] = value;
cout << value << " pushed into stack." << endl;
}
}
// Pop operation
void pop() {
if (isEmpty()) {
cout << "Stack Underflow! Cannot pop." << endl;
} else {
cout << arr[top] << " popped from stack." << endl;
top--;
}
}
// Peek operation: get top element without removing
void peek() {
if (isEmpty()) {
cout << "Stack is empty." << endl;
} else {
cout << "Top element is: " << arr[top] << endl;
}
}
// Display all elements (top to bottom)
void display() {
if (isEmpty()) {
cout << "Stack is empty." << endl;
} else {
cout << "Stack elements (top to bottom): ";
for (int i = top; i >= 0; i--) {
cout << arr[i] << " ";
}
cout << endl;
}
}
};
int main() {
Stack s;
cout << "=== Push Operations ===" << endl;
s.push(10);
s.push(20);
s.push(30);
s.display(); // 30 20 10
cout << "\n=== Peek ===" << endl;
s.peek(); // 30
cout << "\n=== Pop Operations ===" << endl;
s.pop(); // 30
s.pop(); // 20
s.display(); // 10
cout << "\n=== Stack Overflow Test ===" << endl;
s.push(40);
s.push(50);
s.push(60);
s.push(70);
s.push(80); // Overflow (MAX = 5, but we only have 3 after pops)
s.push(90); // Overflow
cout << "\n=== Stack Underflow Test ===" << endl;
s.pop(); s.pop(); s.pop(); s.pop(); s.pop(); // Pop all
s.pop(); // Underflow
return 0;
}
Output:
=== Push Operations ===
10 pushed into stack.
20 pushed into stack.
30 pushed into stack.
Stack elements (top to bottom): 30 20 10
=== Peek ===
Top element is: 30
=== Pop Operations ===
30 popped from stack.
20 popped from stack.
Stack elements (top to bottom): 10
=== Stack Overflow Test ===
40 pushed into stack.
50 pushed into stack.
60 pushed into stack.
70 pushed into stack.
80 pushed into stack.
Stack Overflow! Cannot push 90
=== Stack Underflow Test ===
80 popped from stack.
70 popped from stack.
60 popped from stack.
50 popped from stack.
40 popped from stack.
10 popped from stack.
Stack Underflow! Cannot pop.
3. Stack Implementation Using Linked List
A linked list provides dynamic sizing, allowing the stack to grow and shrink without compile-time capacity limitations.
Example 3: Complete Stack Class (Linked List-Based)
#include <iostream>
using namespace std;
// Node structure
template <class T>
class Node {
public:
T data;
Node* next;
Node(T value) {
data = value;
next = nullptr;
}
};
// Stack class using Linked List
template <class T>
class Stack {
private:
Node<T>* top; // Pointer to top node
public:
// Constructor
Stack() {
top = nullptr;
}
// Destructor (clean up memory)
~Stack() {
while (!isEmpty()) {
pop();
}
}
// Check if stack is empty
bool isEmpty() {
return (top == nullptr);
}
// Push operation
void push(T value) {
Node<T>* newNode = new Node<T>(value);
newNode->next = top; // New node points to old top
top = newNode; // Update top
cout << value << " pushed into stack." << endl;
}
// Pop operation
void pop() {
if (isEmpty()) {
cout << "Stack Underflow! Cannot pop." << endl;
} else {
cout << top->data << " popped from stack." << endl;
Node<T>* temp = top;
top = top->next;
delete temp;
}
}
// Peek operation
void peek() {
if (isEmpty()) {
cout << "Stack is empty." << endl;
} else {
cout << "Top element is: " << top->data << endl;
}
}
// Display all elements
void display() {
if (isEmpty()) {
cout << "Stack is empty." << endl;
} else {
cout << "Stack elements (top to bottom): ";
Node<T>* temp = top;
while (temp != nullptr) {
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
}
};
int main() {
Stack<int> s;
cout << "=== Integer Stack ===" << endl;
s.push(10);
s.push(20);
s.push(30);
s.display(); // 30 20 10
s.peek(); // 30
s.pop(); // 30
s.display(); // 20 10
cout << "\n=== String Stack ===" << endl;
Stack<string> strStack;
strStack.push("Alice");
strStack.push("Bob");
strStack.push("Carol");
strStack.display(); // Carol Bob Alice
return 0;
}
Output:
=== Integer Stack ===
10 pushed into stack.
20 pushed into stack.
30 pushed into stack.
Stack elements (top to bottom): 30 20 10
Top element is: 30
30 popped from stack.
Stack elements (top to bottom): 20 10
=== String Stack ===
Alice pushed into stack.
Bob pushed into stack.
Carol pushed into stack.
Stack elements (top to bottom): Carol Bob Alice
4. Implementation Comparison: Array vs. Linked List
| Feature | Array-Based Stack (Example 2) | Linked List-Based Stack (Example 3) |
|---|---|---|
| Storage Structure | Fixed-size array (int arr[MAX]) | Dynamic heap nodes (Node<T>*) |
| Capacity | Fixed compile-time bound (MAX = 5) | Dynamic (grows on demand) |
| Top Pointer | Integer index (int top) | Node pointer (Node<T>* top) |
| Empty Check | top == -1 | top == nullptr |
| Full Check | top == MAX - 1 | Not required (no static limit) |
| Overflow Condition | Triggers "Stack Overflow!" on 6th push | Does not overflow |
| Underflow Condition | Triggers "Stack Underflow!" on empty pop | Triggers "Stack Underflow!" on empty pop |
| Memory Cleanup | Automatic stack memory | Explicit ~Stack() destructor calling pop() |
| Generic Types | Hardcoded for int | Generic template <class T> (int, string, etc.) |