← Back to DSA Course | Chapter 5: Stacks | Lesson 1 of 5

Stack Introduction

What is a Stack

A stack is a data structure where elements are added and removed from the same end, and the last item put in is always the first one taken out, a rule known as Last In First Out (LIFO).

Example: What is a Stack

#include <iostream>
#include <stack>
using namespace std;
int main() {
    stack<int> s;
    s.push(1); s.push(2); s.push(3);
    cout << "last in, first out -- top is " << s.top() << endl;
    return 0;
}
import java.util.Stack;
public class Main {
    public static void main(String[] args) {
        Stack<Integer> s = new Stack<>();
        s.push(1); s.push(2); s.push(3);
        System.out.println("last in, first out -- top is " + s.peek());
    }
}
s = []
s.append(1)
s.append(2)
s.append(3)
print("last in, first out -- top is", s[-1])
#include <stdio.h>
int main() {
    int s[10], top = -1;
    s[++top] = 1; s[++top] = 2; s[++top] = 3;
    printf("last in, first out -- top is %d\n", s[top]);
    return 0;
}

LIFO Principle

LIFO behaves exactly like a physical pile of plates: you can only add a plate to the top or take one off the top, never reach into the middle, which is exactly what makes a stack simple and predictable to reason about.

Example: LIFO Principle

#include <iostream>
#include <stack>
using namespace std;
int main() {
    stack<string> plates;
    plates.push("plate1"); plates.push("plate2"); plates.push("plate3");
    cout << "take one off the top: " << plates.top() << endl;
    plates.pop();
    cout << "next one off the top: " << plates.top() << endl;
    return 0;
}
import java.util.Stack;
public class Main {
    public static void main(String[] args) {
        Stack<String> plates = new Stack<>();
        plates.push("plate1"); plates.push("plate2"); plates.push("plate3");
        System.out.println("take one off the top: " + plates.pop());
        System.out.println("next one off the top: " + plates.peek());
    }
}
plates = ["plate1", "plate2", "plate3"]
print("take one off the top:", plates.pop())
print("next one off the top:", plates[-1])
#include <stdio.h>
int main() {
    char *plates[3] = {"plate1", "plate2", "plate3"};
    int top = 2;
    printf("take one off the top: %s\n", plates[top--]);
    printf("next one off the top: %s\n", plates[top]);
    return 0;
}

Stack Operations

The core stack operations are push (add to the top), pop (remove from the top), peek (look at the top item without removing it), and a check for whether the stack is currently empty.

Example: Stack Operations

#include <iostream>
#include <stack>
using namespace std;
int main() {
    stack<int> s;
    s.push(10);
    s.push(20);
    cout << "peek: " << s.top() << endl;
    s.pop();
    cout << "after pop, empty? " << s.empty() << endl;
    return 0;
}
import java.util.Stack;
public class Main {
    public static void main(String[] args) {
        Stack<Integer> s = new Stack<>();
        s.push(10); s.push(20);
        System.out.println("peek: " + s.peek());
        s.pop();
        System.out.println("after pop, empty? " + s.isEmpty());
    }
}
s = []
s.append(10)
s.append(20)
print("peek:", s[-1])
s.pop()
print("after pop, empty?", len(s) == 0)
#include <stdio.h>
int main() {
    int s[10], top = -1;
    s[++top] = 10; s[++top] = 20;
    printf("peek: %d\n", s[top]);
    top--;
    printf("after pop, empty? %d\n", top == -1);
    return 0;
}

Stack Applications

Stacks power features you use every day: undo history in an editor, a browser's back button, matching brackets in code, and the function call stack that keeps track of where to return after each function call finishes.

Example: Stack Applications

#include <iostream>
#include <stack>
using namespace std;
int main() {
    stack<char> undoHistory;
    undoHistory.push('A'); undoHistory.push('B'); undoHistory.push('C');
    cout << "undo: reverts " << undoHistory.top() << endl;
    undoHistory.pop();
    cout << "undo again: reverts " << undoHistory.top() << endl;
    return 0;
}
import java.util.Stack;
public class Main {
    public static void main(String[] args) {
        Stack<Character> undoHistory = new Stack<>();
        undoHistory.push('A'); undoHistory.push('B'); undoHistory.push('C');
        System.out.println("undo: reverts " + undoHistory.pop());
        System.out.println("undo again: reverts " + undoHistory.peek());
    }
}
undo_history = ['A', 'B', 'C']
print("undo: reverts", undo_history.pop())
print("undo again: reverts", undo_history[-1])
#include <stdio.h>
int main() {
    char s[10]; int top = -1;
    s[++top] = 'A'; s[++top] = 'B'; s[++top] = 'C';
    printf("undo: reverts %c\n", s[top--]);
    printf("undo again: reverts %c\n", s[top]);
    return 0;
}

Basic Stack Practice

Small exercises like reversing a sequence using a stack, or predicting the output of a series of push/pop operations, are a fast way to build a solid intuition for how LIFO order actually plays out.

Example: Basic Stack Practice

#include <iostream>
#include <stack>
using namespace std;
int main() {
    stack<int> s;
    int arr[] = {1, 2, 3, 4};
    for (int x : arr) s.push(x);
    cout << "reversed: ";
    while (!s.empty()) { cout << s.top() << " "; s.pop(); }
    return 0;
}
import java.util.Stack;
public class Main {
    public static void main(String[] args) {
        Stack<Integer> s = new Stack<>();
        int[] arr = {1, 2, 3, 4};
        for (int x : arr) s.push(x);
        System.out.print("reversed: ");
        while (!s.isEmpty()) System.out.print(s.pop() + " ");
    }
}
s = []
for x in [1, 2, 3, 4]:
    s.append(x)
print("reversed:", end=" ")
while s:
    print(s.pop(), end=" ")
#include <stdio.h>
int main() {
    int s[10], top = -1;
    int arr[] = {1, 2, 3, 4};
    for (int i = 0; i < 4; i++) s[++top] = arr[i];
    printf("reversed: ");
    while (top >= 0) printf("%d ", s[top--]);
    return 0;
}
🔒

Chapter Quiz — Complete all 5 topics to unlock

0/5 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.