<stack>
HeaderThe <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.
#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;
}
std::deque
).push()
is used to add elements to the top of the stack.top()
accesses the top element without removing it.pop()
removes the top element.size()
returns the number of elements in the stack.empty()
checks if the stack is empty.#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;
}
Book
struct to demonstrate using stack with user-defined types.#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;
}
std::deque
), std::vector
, and std::list
.#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;
}
#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;
}
Performance: Operations on a stack are generally constant time O(1), but this can depend on the underlying container.
Memory Usage: The memory usage of a stack depends on its underlying container and the number of elements.
Thread Safety: std::stack
is not thread-safe by default. For concurrent access, external synchronization is needed.
Adaptors vs Containers: Remember that std::stack
is an adaptor, not a container itself. It provides a specific interface to an underlying container.
Limitations: Stack doesn't provide iterators or allow access to elements other than the top, which can be limiting in some scenarios.
The <stack>
header in C++ provides the std::stack
container adapter, implementing a Last-In-First-Out (LIFO) data structure:
std::deque
as the default.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.