#1 India's Top IT Training Institute

×

About Uncodemy

Know more about who we are and what we stand for.

About Us

About Us

Discover our mission to equip individuals with essential IT skills and industry expertise.

Read More →
UnCodeMy Gallery

UnCodeMy Gallery

Explore highlights from our IT training sessions and success stories.

Read More →
×

Free Resources

Learn, practice and plan your career — bilkul free.

Tutorials

Tutorials

Step-by-step written tutorials to learn any technology at your own pace.

Read More →
Free Counselling

Free Counselling

Book a free video counselling session and pick the right course for you.

Read More →
Online Compiler

Online Compiler

Write, run and test your code online — no setup required.

Read More →
Linear Data Structures

Stack in Data Structures: Implementations in Java, Python, & C++

A Stack is a linear data structure that follows the LIFO (Last-In-First-Out) principle. The last element added to the stack is the first one to be removed. It is analogous to a stack of plates — you add a plate on top and remove it from the top.

Basic Operations

  • push(element): Adds an element to the top of the stack.
  • pop(): Removes and returns the top element from the stack.
  • peek() / top(): Returns the top element without removing it.
  • isEmpty(): Checks if the stack is empty.
  • size(): Returns the number of elements in the stack.

Implementation Options

Stacks can be implemented using:

  • Arrays: Fixed size, efficient O(1) operations, but can overflow.
  • Dynamic Arrays (ArrayList): Resizable, O(1) amortized.
  • Linked Lists: Dynamic size, O(1) operations, no overflow.

Implementation in Python

Using List (Dynamic Array)

class Stack:
    def __init__(self):
        self.stack = []

    def push(self, item):
        self.stack.append(item)

    def pop(self):
        if self.is_empty():
            raise IndexError("Stack is empty")
        return self.stack.pop()

    def peek(self):
        if self.is_empty():
            raise IndexError("Stack is empty")
        return self.stack[-1]

    def is_empty(self):
        return len(self.stack) == 0

    def size(self):
        return len(self.stack)

# Example usage
s = Stack()
s.push(10)
s.push(20)
s.push(30)
print(s.peek())   # Output: 30
print(s.pop())    # Output: 30
print(s.size())   # Output: 2

Using Linked List

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class Stack:
    def __init__(self):
        self.top = None
        self._size = 0

    def push(self, item):
        new_node = Node(item)
        new_node.next = self.top
        self.top = new_node
        self._size += 1

    def pop(self):
        if self.is_empty():
            raise IndexError("Stack is empty")
        data = self.top.data
        self.top = self.top.next
        self._size -= 1
        return data

    def peek(self):
        if self.is_empty():
            raise IndexError("Stack is empty")
        return self.top.data

    def is_empty(self):
        return self.top is None

    def size(self):
        return self._size

Implementation in Java

Using ArrayList

import java.util.ArrayList;

class Stack {
    private ArrayList stack;

    public Stack() {
        stack = new ArrayList<>();
    }

    public void push(int item) {
        stack.add(item);
    }

    public int pop() {
        if (isEmpty()) {
            throw new RuntimeException("Stack is empty");
        }
        return stack.remove(stack.size() - 1);
    }

    public int peek() {
        if (isEmpty()) {
            throw new RuntimeException("Stack is empty");
        }
        return stack.get(stack.size() - 1);
    }

    public boolean isEmpty() {
        return stack.isEmpty();
    }

    public int size() {
        return stack.size();
    }
}

// Example usage
class Main {
    public static void main(String[] args) {
        Stack s = new Stack();
        s.push(10);
        s.push(20);
        s.push(30);
        System.out.println(s.peek());  // Output: 30
        System.out.println(s.pop());   // Output: 30
        System.out.println(s.size());  // Output: 2
    }
}

Using Java's Built-in Stack

import java.util.Stack;

public class Main {
    public static void main(String[] args) {
        Stack stack = new Stack<>();
        stack.push(10);
        stack.push(20);
        stack.push(30);
        System.out.println(stack.peek());  // Output: 30
        System.out.println(stack.pop());   // Output: 30
        System.out.println(stack.size());  // Output: 2
    }
}

Using Linked List (Custom)

class Node {
    int data;
    Node next;

    Node(int data) {
        this.data = data;
        this.next = null;
    }
}

class Stack {
    private Node top;
    private int size;

    public Stack() {
        top = null;
        size = 0;
    }

    public void push(int item) {
        Node newNode = new Node(item);
        newNode.next = top;
        top = newNode;
        size++;
    }

    public int pop() {
        if (isEmpty()) {
            throw new RuntimeException("Stack is empty");
        }
        int data = top.data;
        top = top.next;
        size--;
        return data;
    }

    public int peek() {
        if (isEmpty()) {
            throw new RuntimeException("Stack is empty");
        }
        return top.data;
    }

    public boolean isEmpty() {
        return top == null;
    }

    public int size() {
        return size;
    }
}

Implementation in C++

Using Vector (Dynamic Array)

#include 
#include 
using namespace std;

class Stack {
private:
    vector stack;

public:
    void push(int item) {
        stack.push_back(item);
    }

    int pop() {
        if (isEmpty()) {
            throw runtime_error("Stack is empty");
        }
        int item = stack.back();
        stack.pop_back();
        return item;
    }

    int peek() {
        if (isEmpty()) {
            throw runtime_error("Stack is empty");
        }
        return stack.back();
    }

    bool isEmpty() {
        return stack.empty();
    }

    int size() {
        return stack.size();
    }
};

// Example usage
int main() {
    Stack s;
    s.push(10);
    s.push(20);
    s.push(30);
    cout << s.peek() << endl;  // Output: 30
    cout << s.pop() << endl;   // Output: 30
    cout << s.size() << endl;  // Output: 2
    return 0;
}

Using C++ STL Stack

#include 
#include 
using namespace std;

int main() {
    stack s;
    s.push(10);
    s.push(20);
    s.push(30);
    cout << s.top() << endl;   // Output: 30
    s.pop();
    cout << s.top() << endl;   // Output: 20
    cout << s.size() << endl;  // Output: 2
    return 0;
}

Using Linked List (Custom)

#include 
using namespace std;

struct Node {
    int data;
    Node* next;
    Node(int val) : data(val), next(nullptr) {}
};

class Stack {
private:
    Node* top;
    int size;

public:
    Stack() : top(nullptr), size(0) {}

    void push(int item) {
        Node* newNode = new Node(item);
        newNode->next = top;
        top = newNode;
        size++;
    }

    int pop() {
        if (isEmpty()) {
            throw runtime_error("Stack is empty");
        }
        int data = top->data;
        Node* temp = top;
        top = top->next;
        delete temp;
        size--;
        return data;
    }

    int peek() {
        if (isEmpty()) {
            throw runtime_error("Stack is empty");
        }
        return top->data;
    }

    bool isEmpty() {
        return top == nullptr;
    }

    int getSize() {
        return size;
    }

    ~Stack() {
        while (!isEmpty()) {
            pop();
        }
    }
};

Complexity Analysis

OperationArray ImplementationDynamic Array (Amortized)Linked List Implementation
pushO(1)O(1)O(1)
popO(1)O(1)O(1)
peekO(1)O(1)O(1)
isEmptyO(1)O(1)O(1)
sizeO(1)O(1)O(1)
SpaceO(n) fixedO(n)O(n)

Applications of Stack

  • Function Call Management: The call stack stores function calls, local variables, and return addresses.
  • Expression Evaluation: Converting infix to postfix/prefix and evaluating expressions (e.g., calculators).
  • Undo/Redo Operations: In text editors and applications.
  • Backtracking: Algorithms like DFS, maze solving, N-Queens.
  • Parsing: Checking balanced parentheses, XML/HTML tag matching.
  • Browser Navigation: Back and forward buttons.
  • Recursion: The recursive call mechanism is implemented using a stack.
  • Memory Management: Stack memory allocation for local variables.

Advantages & Disadvantages

Advantages

  • Simple: Easy to understand and implement.
  • Fast: All operations are O(1).
  • Memory Efficient: Only stores the data needed.
  • Dynamic: Can grow/shrink dynamically with linked list or dynamic array.

Disadvantages

  • Limited Access: You can only access the top element.
  • Fixed Size (array implementation): May overflow if not sized correctly.
  • No Random Access: Cannot access elements by index.

Common Stack Problems

  • Balanced Parentheses: Check if parentheses are properly matched.
  • Next Greater Element: Find the next greater element for each element.
  • Valid Parentheses: Check if brackets are valid.
  • Evaluate Postfix Expression: Evaluate a postfix expression.
  • Stock Span Problem: Calculate span of stock prices.
  • Largest Rectangle in Histogram: Find largest rectangular area.

Key Takeaways

  • Stack follows the LIFO (Last-In-First-Out) principle.
  • Basic operations: push, pop, peek, isEmpty, size — all O(1).
  • Can be implemented using arrays, dynamic arrays, or linked lists.
  • Widely used in function calls, expression evaluation, undo/redo, and backtracking.
  • Essential for many interview problems and algorithmic challenges.

Ready to master Data Structures & Algorithms?

Learn DSA hands-on with mentor-led sessions, real interview practice, and placement support.

Explore Course