SrcForge

Lesson 44

Stack

Covers creating a stack, characteristics of stacks, common stack operations, how a stack works internally, and processing elements in LIFO order.

Lesson content

What is STL Stack in C++?

A stack is a container adapter in the Standard Template Library (STL) that stores elements according to the LIFO (Last In, First Out) principle.

This means the last element inserted is the first element removed.

Think of a stack as a stack of books. You place a new book on the top, and when you want to remove one, you always take the top book first.

Unlike std::vector or std::deque, a stack only allows operations on the top element.

Why does STL Stack exist?

Many real-world applications require processing the most recently added item before older ones. Instead of implementing LIFO behavior manually, C++ provides std::stack.

  • Simplifies LIFO operations
  • Restricts access to prevent accidental modifications
  • Provides efficient insertion and removal at the top
  • Makes code easier to understand and maintain

Real-world use cases

  • Undo/redo operations
  • Browser back button
  • Function call management (call stack)
  • Expression evaluation
  • Parentheses matching
  • Depth-First Search (DFS)
  • Syntax parsing in compilers
  • Backtracking algorithms

Prerequisites

  • Variables and data types
  • Arrays
  • Functions
  • Loops
  • Templates
  • Basic STL containers (vector and deque)

Including the header

#include <stack>

Creating a stack

stack<data_type> stack_name;

// Example:
stack<int> numbers;

Characteristics of STL Stack

  • Access method: LIFO (Last In, First Out)
  • Top insertion: allowed
  • Top removal: allowed
  • Random access: not supported
  • Iterators: not available
  • Default underlying container: std::deque

Common stack operations

  • push() – add an element to the top
  • pop() – remove the top element
  • top() – access the top element
  • size() – number of elements
  • empty() – check whether the stack is empty

How a stack works

Suppose we insert 10, 20, 30. The stack looks like: Top → 30, 20, 10. Calling pop() removes 30, leaving Top → 20, 10. The newest element is always removed first.

Underlying container

By default, std::stack uses std::deque internally. You can also use std::vector or std::list.

stack<int, vector<int>> s;

Example 1: Creating and using a stack

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

int main()
{
    stack<int> numbers;

    numbers.push(10);
    numbers.push(20);
    numbers.push(30);

    cout << numbers.top();

    return 0;
}

// Output: 30

Example 2: Removing elements

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

int main()
{
    stack<int> values;

    values.push(100);
    values.push(200);
    values.push(300);

    values.pop();

    cout << values.top();

    return 0;
}

// Output: 200

Example 3: Processing all elements

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

int main()
{
    stack<int> numbers;

    numbers.push(1);
    numbers.push(2);
    numbers.push(3);

    while (!numbers.empty())
    {
        cout << numbers.top();
        cout << " ";

        numbers.pop();
    }

    return 0;
}

// Output: 3 2 1

Example 4: Parentheses matching

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

int main()
{
    string expression = "{[()]}";

    stack<char> symbols;

    for (char ch : expression)
    {
        if (ch == '(' || ch == '[' || ch == '{')
        {
            symbols.push(ch);
        }
        else
        {
            if (!symbols.empty())
            {
                symbols.pop();
            }
        }
    }

    if (symbols.empty())
    {
        cout << "Balanced";
    }
    else
    {
        cout << "Not Balanced";
    }

    return 0;
}

// Output: Balanced
// Note: This simplified example demonstrates the basic idea. A complete
// solution should also verify that each closing bracket matches the
// correct type of opening bracket.

Example 5: Browser back history

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

int main()
{
    stack<string> history;

    history.push("Home");
    history.push("Products");
    history.push("Checkout");

    cout << "Current Page: ";
    cout << history.top() << endl;

    history.pop();

    cout << "After Back: ";
    cout << history.top() << endl;

    return 0;
}

Common mistakes and pitfalls

  • Trying to access elements with s[0]. Fix: use top() to access the top element
  • Calling top() on an empty stack. Fix: check empty() first
  • Assuming pop() returns the removed element. Fix: use top() before calling pop()
  • Trying to iterate through a stack. Fix: stacks do not provide iterators
  • Using a stack when FIFO behavior is required. Fix: use std::queue instead

Best practices

  • Always check empty() before calling top() or pop()
  • Use stacks only for LIFO operations
  • Process elements using a while (!stack.empty()) loop
  • Store lightweight objects or smart pointers for large data
  • Use the default underlying std::deque unless a different container is specifically required

When not to use this

  • FIFO processing is required (use std::queue)
  • Random access is needed (use std::vector)
  • You need to iterate through elements without removing them
  • Elements must remain sorted (use std::priority_queue or std::set)
  • Frequent insertions or deletions are needed in the middle of the collection

Summary

  • STL Stack in C++ is a LIFO (Last In, First Out) container adapter
  • Elements are added using push() and removed using pop()
  • The top element is accessed with top()
  • Common operations include push(), pop(), top(), size(), and empty()
  • A stack does not support indexing, iterators, or random access
  • Use std::stack whenever the most recently added element should be processed first

Frequently asked questions

What is the difference between a stack and a queue?

A stack follows the LIFO (Last In, First Out) principle, while a queue follows the FIFO (First In, First Out) principle.

Why doesn't pop() return the removed element?

The STL separates element access and removal. Call top() to read the element, then pop() to remove it.

Can I iterate through a stack?

No. std::stack does not provide iterators. To process all elements, repeatedly access top() and remove it with pop() until the stack is empty.

What is the time complexity of stack operations?

For the default underlying std::deque, push(), pop(), top(), empty(), and size() are all O(1).

When should I use std::stack instead of std::vector?

Use std::stack when you want to enforce LIFO behavior and prevent random access to elements. Use std::vector when you need indexed access, iteration, or more flexibility.