stack


C++ <stack> Header

The <stack> header is part of the C++ Standard Template Library (STL) that provides the std::stack container adapter. A stack is a Last-In-First-Out (LIFO) data structure, where elements are inserted and removed only from one end, called the top of the stack. This container adapter is implemented on top of other container classes like deque (default), vector, or list, providing a specific interface to the underlying container.

Key Characteristics

Example 1: Basic Stack Operations

#include <iostream>
#include <stack>

int main() {
    std::stack<int> myStack;

    // Pushing elements
    myStack.push(10);
    myStack.push(20);
    myStack.push(30);

    std::cout << "Stack size: " << myStack.size() << std::endl;
    std::cout << "Top element: " << myStack.top() << std::endl;

    // Popping elements
    myStack.pop();
    std::cout << "After pop, top element: " << myStack.top() << std::endl;

    // Checking if stack is empty
    std::cout << "Is stack empty? " << (myStack.empty() ? "Yes" : "No") << std::endl;

    return 0;
}

Explanation:

2. Using Stack with Custom Types

#include <iostream>
#include <stack>
#include <string>

struct Book {
    std::string title;
    int year;

    Book(std::string t, int y) : title(std::move(t)), year(y) {}
};

int main() {
    std::stack<Book> bookStack;

    bookStack.push({"The C++ Programming Language", 2013});
    bookStack.push({"Effective Modern C++", 2014});
    bookStack.push({"C++ Concurrency in Action", 2019});

    std::cout << "Books in stack:" << std::endl;
    while (!bookStack.empty()) {
        const Book& book = bookStack.top();
        std::cout << book.title << " (" << book.year << ")" << std::endl;
        bookStack.pop();
    }

    return 0;
}

Explanation:

Example 3: Stack with Different Underlying Container

#include <iostream>
#include <stack>
#include <vector>
#include <list>

template <typename T>
void printStackInfo(const std::stack<T>& s) {
    std::cout << "Stack size: " << s.size() 
              << ", Top element: " << (s.empty() ? 0 : s.top()) << std::endl;
}

int main() {
    std::stack<int> defaultStack;
    std::stack<int, std::vector<int>> vectorStack;
    std::stack<int, std::list<int>> listStack;

    for (int i = 1; i <= 5; ++i) {
        defaultStack.push(i);
        vectorStack.push(i * 10);
        listStack.push(i * 100);
    }

    std::cout << "Default stack (deque): ";
    printStackInfo(defaultStack);

    std::cout << "Vector-based stack: ";
    printStackInfo(vectorStack);

    std::cout << "List-based stack: ";
    printStackInfo(listStack);

    return 0;
}

Explanation:

Example 4: Implementing a Simple Calculator using Stack

#include <iostream>
#include <stack>
#include <string>
#include <sstream>

int evaluatePostfix(const std::string& expression) {
    std::stack<int> stack;
    std::istringstream iss(expression);
    std::string token;

    while (iss >> token) {
        if (isdigit(token[0])) {
            stack.push(std::stoi(token));
        } else {
            int operand2 = stack.top(); stack.pop();
            int operand1 = stack.top(); stack.pop();

            switch (token[0]) {
                case '+': stack.push(operand1 + operand2); break;
                case '-': stack.push(operand1 - operand2); break;
                case '*': stack.push(operand1 * operand2); break;
                case '/': stack.push(operand1 / operand2); break;
            }
        }
    }

    return stack.top();
}

int main() {
    std::string expression = "5 3 + 2 * 4 -";
    std::cout << "Postfix expression: " << expression << std::endl;
    std::cout << "Result: " << evaluatePostfix(expression) << std::endl;

    return 0;
}

Explanation:

Example 5: Checking for Balanced Parentheses

#include <iostream>
#include <stack>
#include <string>

bool areParenthesesBalanced(const std::string& expression) {
    std::stack<char> stack;

    for (char c : expression) {
        if (c == '(' || c == '[' || c == '{') {
            stack.push(c);
        } else if (c == ')' || c == ']' || c == '}') {
            if (stack.empty()) return false;

            char top = stack.top();
            stack.pop();

            if ((c == ')' && top != '(') ||
                (c == ']' && top != '[') ||
                (c == '}' && top != '{')) {
                return false;
            }
        }
    }

    return stack.empty();
}

int main() {
    std::string expr1 = "{[()]}";
    std::string expr2 = "([)]";
    std::string expr3 = "((";

    std::cout << expr1 << " is " << (areParenthesesBalanced(expr1) ? "balanced" : "not balanced") << std::endl;
    std::cout << expr2 << " is " << (areParenthesesBalanced(expr2) ? "balanced" : "not balanced") << std::endl;
    std::cout << expr3 << " is " << (areParenthesesBalanced(expr3) ? "balanced" : "not balanced") << std::endl;

    return 0;
}

Explanation:

Additional Considerations

  1. Performance: Operations on a stack are generally constant time O(1), but this can depend on the underlying container.

  2. Memory Usage: The memory usage of a stack depends on its underlying container and the number of elements.

  3. Thread Safety: std::stack is not thread-safe by default. For concurrent access, external synchronization is needed.

  4. Adaptors vs Containers: Remember that std::stack is an adaptor, not a container itself. It provides a specific interface to an underlying container.

  5. Limitations: Stack doesn't provide iterators or allow access to elements other than the top, which can be limiting in some scenarios.

Summary

The <stack> header in C++ provides the std::stack container adapter, implementing a Last-In-First-Out (LIFO) data structure:

The std::stack is an essential tool in a C++ programmer's toolkit, particularly useful in parsing, algorithm implementation, and memory management scenarios. Its simplicity and efficiency make it a go-to choice when LIFO behavior is needed. However, its restricted interface means that for more complex data manipulation, other container types might be more appropriate. Understanding when and how to use std::stack effectively can lead to cleaner, more efficient code in many algorithmic and data processing applications.

Related

Previous Page | Course Schedule | Course Content