C++ Stack

Understanding Last-In-First-Out (LIFO) containers

📚 What is C++ Stack?

C++ Stack is a container adapter that follows LIFO (Last-In-First-Out) principle. Elements are added and removed from the top only, like a stack of plates.


#include <iostream>
#include <stack>
using namespace std;

int main() {
    stack<int> myStack;
    
    myStack.push(10);
    myStack.push(20);
    myStack.push(30);
    
    cout << "Top: " << myStack.top() << endl;
    
    return 0;
}
                                    

Output:

Top: 30

Key Stack Operations

⬆️

Push

Add element to the top of stack

myStack.push(42);
⬇️

Pop

Remove top element from stack

myStack.pop();
👁️

Top

Access the top element

int topElement = myStack.top();

Empty & Size

Check if stack is empty or get size

bool isEmpty = myStack.empty();
int size = myStack.size();

🔹 Basic Stack Operations

Stacks are LIFO (Last-In, First-Out) data structures providing push, pop, and top operations for managing elements in reverse order. The C++ std::stack adapter typically uses a deque or vector as its underlying container. Key operations include push to add, pop to remove the top, and top to inspect without removal. Stacks are fundamental for undo mechanisms, recursion simulation, expression evaluation, and depth-first search. Their simplicity and constrained interface make them reliable for controlling access order, ensuring elements are processed in the exact reverse sequence of their addition.

#include <iostream>
#include <stack>
using namespace std;

int main() {
    stack<string> books;
    
    // Push books onto stack
    books.push("C++ Primer");
    books.push("Effective C++");
    books.push("Modern C++");
    
    cout << "Stack size: " << books.size() << endl;
    cout << "Top book: " << books.top() << endl;
    
    // Remove books from stack (LIFO order)
    cout << "\nRemoving books:" << endl;
    while(!books.empty()) {
        cout << books.top() << endl;
        books.pop();
    }
    
    cout << "Stack is now empty: " << (books.empty() ? "Yes" : "No") << endl;
    
    return 0;
}

Output:

Stack size: 3
Top book: Modern C++

Removing books:
Modern C++
Effective C++
C++ Primer
Stack is now empty: Yes

🔹 Stack for Expression Evaluation

Stacks are algorithmically central to evaluating postfix expressions and checking syntax, like balanced parentheses in code. For expression evaluation, operands are pushed onto the stack, and operators pop the required operands, compute, and push the result. For balancing, an opening symbol is pushed, and a closing symbol must match the top before popping. This LIFO behavior perfectly matches nested structures. This makes stacks indispensable in compilers, calculators, and parsers, providing an efficient, intuitive mechanism for handling nested or hierarchical data and operations.

#include <iostream>
#include <stack>
#include <string>
using namespace std;

bool isBalanced(string expression) {
    stack<char> brackets;
    
    for(char ch : expression) {
        if(ch == '(' || ch == '[' || ch == '{') {
            brackets.push(ch);
        }
        else if(ch == ')' || ch == ']' || ch == '}') {
            if(brackets.empty()) return false;
            
            char top = brackets.top();
            brackets.pop();
            
            if((ch == ')' && top != '(') ||
               (ch == ']' && top != '[') ||
               (ch == '}' && top != '{')) {
                return false;
            }
        }
    }
    
    return brackets.empty();
}

int main() {
    string expr1 = "{[()]}";
    string expr2 = "{[(])}";
    
    cout << expr1 << " is " << (isBalanced(expr1) ? "balanced" : "not balanced") << endl;
    cout << expr2 << " is " << (isBalanced(expr2) ? "balanced" : "not balanced") << endl;
    
    return 0;
}

Output:

{[()]} is balanced
{[(])} is not balanced

🔹 Stack for Undo Operations

Implementing undo functionality naturally aligns with the stack’s LIFO principle, where each action is pushed and undone by popping. Each user action (like text insertion) is recorded as a state or command object on the stack. An undo operation pops the most recent action, reverting to the previous state. This provides a clean, bounded history. Stacks ensure undo operations occur in the exact reverse order of execution, a requirement for coherent user experience in editors, graphics software, and transactional systems. This pattern is a classic and effective use of the stack data structure.

#include <iostream>
#include <stack>
#include <string>
using namespace std;

class TextEditor {
private:
    string text;
    stack<string> history;
    
public:
    void write(string newText) {
        history.push(text);  // Save current state
        text += newText;
        cout << "Added: " << newText << endl;
        cout << "Current text: " << text << endl;
    }
    
    void undo() {
        if(!history.empty()) {
            text = history.top();
            history.pop();
            cout << "Undo successful" << endl;
            cout << "Current text: " << text << endl;
        } else {
            cout << "Nothing to undo" << endl;
        }
    }
};

int main() {
    TextEditor editor;
    
    editor.write("Hello ");
    editor.write("World!");
    editor.undo();
    editor.undo();
    editor.undo();  // Nothing to undo
    
    return 0;
}

Output:

Added: Hello
Current text: Hello
Added: World!
Current text: Hello World!
Undo successful
Current text: Hello
Undo successful
Current text:
Nothing to undo

🧠 Test Your Knowledge

What principle does a stack follow?