DEV Community

Harsh Mishra
Harsh Mishra

Posted on

Stack: Container, C++

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

  1. Introduction to Stack in C++
  2. Different Ways to Construct a Stack
  3. Common Operations on Stack
    • push()
    • pop()
    • top()
    • empty()
    • size()
  4. Working with Custom Data Types
  5. 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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

Example:

stack<int> s;
s.push(10);
s.push(20);
s.push(30);
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

Example:

stack<int> s;
s.push(10);
s.push(20);
s.push(30);
s.pop(); // Removes 30
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

Example:

stack<int> s;
s.push(10);
s.push(20);
s.push(30);
cout << "Top element: " << s.top() << endl; // Outputs 30
Enter fullscreen mode Exit fullscreen mode

3.4 empty()

The empty() function checks whether the stack is empty.

Syntax:

bool isEmpty = s.empty();
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

3.5 size()

The size() function returns the number of elements in the stack.

Syntax:

size_t stackSize = s.size();
Enter fullscreen mode Exit fullscreen mode

Example:

stack<int> s;
s.push(10);
s.push(20);
cout << "Stack size: " << s.size() << endl; // Outputs 2
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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, and size() 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:

  1. Check for empty before popping: Always check if the stack is empty using empty() before calling pop(). Popping from an empty stack is undefined behavior.
  2. 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.
  3. 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)