In C++, the stack
container is a part of the Standard Template Library (STL) and provides a simple way to manage data in a LIFO (Last In, First Out) manner. In this guide, we will explore all the ways to construct a stack, its various functions like push
, pop
, top
, empty
, size
, and more. Whether you're a beginner or an advanced C++ programmer, this guide will walk you through everything you need to know to effectively use the stack
container in C++.
Table of Contents
- Introduction to Stack in C++
- Different Ways to Construct a Stack
-
Common Operations on Stack
push()
pop()
top()
empty()
size()
- Working with Custom Data Types
- Summary and Best Practices
1. Introduction to Stack in C++
In C++, a stack is a container adaptor, which means it is built on top of other underlying containers such as deque
, vector
, or list
. The stack is designed to operate in a last-in-first-out (LIFO) manner, meaning the most recently added element is the first to be removed.
You can think of a stack as a stack of plates, where you can only add or remove plates from the top of the stack.
Key Features:
- Push: Adds an element to the top of the stack.
- Pop: Removes the element from the top of the stack.
- Top: Retrieves the element at the top of the stack without removing it.
- Size: Returns the number of elements in the stack.
- Empty: Checks if the stack is empty.
2. Different Ways to Construct a Stack
The stack
container in C++ can be constructed in several ways, depending on the underlying container used and the required behavior.
2.1 Default Constructor
A stack can be created using the default constructor, which uses deque
as the underlying container by default.
stack<int> s;
In this example, s
is an empty stack of integers. It will use a deque
to store the elements.
2.2 Constructor with an Initial Container
You can create a stack by passing an existing container such as deque
, vector
, or list
to the stack constructor. The stack will be initialized with the elements from the given container.
vector<int> v = {1, 2, 3, 4};
stack<int, vector<int>> s(v);
Here, the stack s
is initialized directly with the elements of the vector
v
.
Similarly, you can use a deque
or list
to initialize the stack:
list<int> l = {1, 2, 3, 4};
stack<int, list<int>> s(l);
In these examples, the stack s
is initialized with the elements from the vector
v
or the list
l
.
2.3 Stack with Custom Container
You can also specify a different underlying container, such as list
, by providing it as a template parameter. This allows you to customize the stack's behavior by choosing the properties of the underlying container.
stack<int, list<int>> s;
This creates a stack with a list<int>
as the underlying container, rather than the default deque
. Similarly, you can use other containers like vector
or deque
depending on your requirements.
3. Common Operations on Stack
3.1 push()
The push()
function adds an element to the top of the stack.
Syntax:
s.push(element);
Example:
stack<int> s;
s.push(10);
s.push(20);
s.push(30);
After this code, the stack s
will contain the elements: 10 at the bottom, 20 in the middle, and 30 at the top.
3.2 pop()
The pop()
function removes the top element of the stack.
Syntax:
s.pop();
Example:
stack<int> s;
s.push(10);
s.push(20);
s.push(30);
s.pop(); // Removes 30
After calling pop()
, the top of the stack will be 20.
3.3 top()
The top()
function retrieves the top element of the stack without removing it.
Syntax:
element = s.top();
Example:
stack<int> s;
s.push(10);
s.push(20);
s.push(30);
cout << "Top element: " << s.top() << endl; // Outputs 30
3.4 empty()
The empty()
function checks whether the stack is empty.
Syntax:
bool isEmpty = s.empty();
Example:
stack<int> s;
cout << "Is stack empty? " << (s.empty() ? "Yes" : "No") << endl; // Outputs Yes
s.push(10);
cout << "Is stack empty? " << (s.empty() ? "Yes" : "No") << endl; // Outputs No
3.5 size()
The size()
function returns the number of elements in the stack.
Syntax:
size_t stackSize = s.size();
Example:
stack<int> s;
s.push(10);
s.push(20);
cout << "Stack size: " << s.size() << endl; // Outputs 2
4. Working with Custom Data Types
You can also use stacks with custom data types. Let's create a custom class and use it with the stack container.
Example: Stack with Custom Object
#include <iostream>
#include <stack>
using namespace std;
class Book {
public:
string title;
string author;
Book(string t, string a) : title(t), author(a) {}
void display() {
cout << "Title: " << title << ", Author: " << author << endl;
}
};
int main() {
stack<Book> bookStack;
bookStack.push(Book("1984", "George Orwell"));
bookStack.push(Book("Brave New World", "Aldous Huxley"));
// Display top book
bookStack.top().display(); // Outputs: Title: Brave New World, Author: Aldous Huxley
bookStack.pop();
bookStack.top().display(); // Outputs: Title: 1984, Author: George Orwell
return 0;
}
In this example, we create a custom class Book
and push Book
objects onto the stack. The top()
function retrieves the Book
object from the stack, and the pop()
function removes it.
5. Summary and Best Practices
- Stack Construction: You can construct stacks in various ways — using the default constructor, by passing an existing container, or by specifying a custom underlying container.
-
Operations: Use
push()
to add elements,pop()
to remove the top element,top()
to peek at the top element,empty()
to check if the stack is empty, andsize()
to get the number of elements in the stack. - Custom Types: Stacks can also store custom data types, and you can manipulate them just like any other data types.
Best Practices:
-
Check for empty before popping: Always check if the stack is empty using
empty()
before callingpop()
. Popping from an empty stack is undefined behavior. -
Use appropriate containers: If you need fast access to elements at both ends, consider using
deque
as the underlying container for your stack. If only fast push/pop operations are required,vector
is also a good choice. -
No direct iteration: The
stack
container does not allow direct iteration through its elements. If you need to access all elements, you will have to pop them one by one.
By understanding these fundamental operations and their usage, you can leverage the stack
container in C++ to manage data in a LIFO manner efficiently. This container is ideal for situations like undo mechanisms, parsing expressions, and managing function calls (such as in recursion).
Top comments (0)