๐ STL Container Adapters: Stack, Queue & Priority Queue
๐ญ The Restaurant Kitchen Story
Imagine youโre running a busy restaurant kitchen. You have three special systems to organize your work:
- A stack of plates ๐ฝ๏ธ - You put clean plates on top, and grab from the top
- A ticket line ๐ซ - First order in, first order served
- A VIP list โญ - Important customers always get served first
These three systems are exactly how C++ Container Adapters work!
๐ฅ Stack Container: The Plate Stack
What is a Stack?
Think of a stack of pancakes. You can only:
- Add a new pancake on top
- Remove a pancake from the top
- Look at the pancake on top
This is called LIFO - Last In, First Out!
graph TD A["Push 10"] --> B["Push 20"] B --> C["Push 30"] C --> D["Top = 30"] D --> E["Pop removes 30"] E --> F["Top = 20 now"]
Creating a Stack
#include <stack>
using namespace std;
// Empty stack of integers
stack<int> plates;
// Stack from another container
deque<int> d = {1, 2, 3};
stack<int> s(d);
Stack Operations
| Operation | What it does | Example |
|---|---|---|
push(x) |
Add on top | s.push(5); |
pop() |
Remove from top | s.pop(); |
top() |
See the top | int x = s.top(); |
empty() |
Is it empty? | if(s.empty()) |
size() |
How many? | int n = s.size(); |
๐ฎ Real Example: Undo Button
stack<string> actions;
// User types
actions.push("Hello");
actions.push("Hello World");
// User clicks Undo!
actions.pop();
// Now back to "Hello"
โ ๏ธ Important Rules
- Never call
top()orpop()on empty stack! pop()doesnโt return the value - usetop()first- Default uses
dequeunderneath
// WRONG - will crash! โ
stack<int> s;
int x = s.top(); // Empty stack!
// RIGHT โ
if (!s.empty()) {
int x = s.top();
s.pop();
}
๐ถ Queue Container: The Waiting Line
What is a Queue?
Think of a line at the ice cream shop.
- First person in line โ gets served first
- New people join at the back
- People leave from the front
This is called FIFO - First In, First Out!
graph LR A["Back"] --> B["3"] B --> C["2"] C --> D["1"] D --> E["Front"] F["New person joins back"] -.-> A E -.-> G["First person leaves"]
Creating a Queue
#include <queue>
using namespace std;
// Empty queue
queue<string> line;
// Queue from deque
deque<int> d = {1, 2, 3};
queue<int> q(d);
Queue Operations
| Operation | What it does | Example |
|---|---|---|
push(x) |
Add to back | q.push("Bob"); |
pop() |
Remove from front | q.pop(); |
front() |
See the front | string s = q.front(); |
back() |
See the back | string s = q.back(); |
empty() |
Is it empty? | if(q.empty()) |
size() |
How many? | int n = q.size(); |
๐ฎ Real Example: Print Jobs
queue<string> printer;
// Add print jobs
printer.push("Report.pdf");
printer.push("Photo.jpg");
printer.push("Letter.doc");
// Process in order
while (!printer.empty()) {
cout << "Printing: "
<< printer.front() << endl;
printer.pop();
}
// Prints: Report, Photo, Letter
๐ Stack vs Queue
| Feature | Stack ๐ฅ | Queue ๐ถ |
|---|---|---|
| Order | LIFO | FIFO |
| Add | Top | Back |
| Remove | Top | Front |
| Use case | Undo, Back button | Lines, Tasks |
โญ Priority Queue: The VIP List
What is a Priority Queue?
Imagine a hospital emergency room:
- Critical patients โ treated first
- Minor injuries โ wait longer
- Itโs not about who came first, itโs about priority!
By default, the biggest number has highest priority.
graph TD A["Add: 10, 30, 20"] --> B["Internal heap"] B --> C["Top = 30 highest!"] C --> D["Pop removes 30"] D --> E["Top = 20 now"]
Creating a Priority Queue
#include <queue>
using namespace std;
// Empty - max priority default
priority_queue<int> pq;
// Min priority - smallest first
priority_queue<int,
vector<int>,
greater<int>> minPQ;
Priority Queue Operations
| Operation | What it does | Example |
|---|---|---|
push(x) |
Add element | pq.push(5); |
pop() |
Remove highest | pq.pop(); |
top() |
See highest | int x = pq.top(); |
empty() |
Is it empty? | if(pq.empty()) |
size() |
How many? | int n = pq.size(); |
๐ฎ Real Example: Task Manager
priority_queue<int> tasks;
tasks.push(3); // Low priority
tasks.push(10); // HIGH priority
tasks.push(5); // Medium
// Process by priority
while (!tasks.empty()) {
cout << tasks.top() << " ";
tasks.pop();
}
// Output: 10 5 3
๐ Min Priority Queue
Want smallest first? Flip it!
// Smallest number = highest priority
priority_queue<int,
vector<int>,
greater<int>> minHeap;
minHeap.push(30);
minHeap.push(10);
minHeap.push(20);
cout << minHeap.top(); // 10 (smallest!)
๐ Custom Priority
For custom objects, define comparison:
struct Task {
string name;
int urgency;
};
// Compare by urgency
auto cmp = [](Task a, Task b) {
return a.urgency < b.urgency;
};
priority_queue<Task,
vector<Task>,
decltype(cmp)> taskQ(cmp);
๐ฏ Quick Comparison Table
| Feature | Stack | Queue | Priority Queue |
|---|---|---|---|
| Order | LIFO | FIFO | By Priority |
| Add | push() |
push() |
push() |
| Remove | pop() |
pop() |
pop() |
| Access | top() |
front()/back() |
top() |
| Underlying | deque | deque | vector + heap |
๐ก When to Use What?
Use Stack when:
- ๐ Undo/Redo functionality
- ๐ Back button navigation
- ๐งฎ Expression evaluation
- ๐ Recursion simulation
Use Queue when:
- ๐จ๏ธ Print job scheduling
- ๐จ Message queues
- ๐ Breadth-first search
- โณ Task scheduling (FIFO)
Use Priority Queue when:
- ๐ฅ Emergency room triage
- ๐ Top-K problems
- ๐บ๏ธ Dijkstraโs algorithm
- โฐ Event scheduling by time
๐ Pro Tips
-
Check before access! Always verify
!empty()beforetop()orfront() -
Remember:
pop()returns nothing - it just removes! -
Default priorities:
priority_queueโ biggest first (max-heap)- Use
greater<int>for smallest first
-
Theyโre adapters! They wrap other containers:
- Stack โ wraps
deque(default) - Queue โ wraps
deque(default) - Priority Queue โ wraps
vector(default)
- Stack โ wraps
๐ You Did It!
You now understand the three container adapters:
- Stack = Plates (LIFO) ๐ฅ
- Queue = Line (FIFO) ๐ถ
- Priority Queue = VIP (Highest first) โญ
These simple containers solve so many real problems. Every time you use an Undo button, process a queue of tasks, or sort by importance - youโre using these concepts!
Go build something amazing! ๐
