<style> .reveal-up, .reveal-left, .reveal-right, .reveal-stagger > * { opacity: 1 !important; transform: none !important; } </style>
  1. Learn
  2. DSA
  3. Linear data structures
All lessons in this course

Lesson 10 of 50 15 minBeginner

Stacks and their uses

Last in, first out: implement a stack on an array, check balanced brackets, build undo/redo, evaluate expressions and meet the monotonic stack pattern.

A stack is a collection where you only touch the top. You push an item onto the top and pop the top item off. The last item in is the first item out: LIFO. Think of a stack of plates, or steel sections loaded onto a truck: the last one loaded is the first one unloaded.

OperationMeaningCost
Push(x)Put x on topO(1) amortised
Pop()Remove and return the topO(1)
Peek()Look at the top without removing itO(1)
CountHow many itemsO(1)

You already use stacks every day: the call stack of your program, Undo in any editor, the Back button in a browser. In algorithms, stacks appear whenever you must handle the most recent unfinished thing first.

A stack is just an array with a top index

ArrayStack.cs
public class ArrayStack<T>{    private T[] _items = new T[4];    private int _count;                       // also the index of the next free slot     public int Count => _count;     public void Push(T item)    {        if (_count == _items.Length)            Array.Resize(ref _items, _items.Length * 2);   // double when full        _items[_count++] = item;    }     public T Pop()    {        if (_count == 0) throw new InvalidOperationException("Stack is empty");        T item = _items[--_count];        _items[_count] = default!;            // release the reference        return item;    }     public T Peek() => _count > 0 ? _items[_count - 1] : throw new InvalidOperationException("Stack is empty");}

Pushing and popping only touch the end of the array, so nothing ever shifts. .NET’s Stack<T> works exactly like this.

Balanced brackets

Compilers and editors must check that every (, [ and { is closed by the right partner in the right order. A stack makes this easy: push every opening bracket; on a closing bracket, the top of the stack must be its partner.

Interactive

Balanced brackets with a stack

Opening brackets are pushed. A closing bracket must match the one on top, which is popped. Step through, or type your own code.

Input
Stack (top first)
empty
Start with an empty stack. Press Step.
IsBalanced.cs
static bool IsBalanced(string code){    var stack = new Stack<char>();    foreach (char c in code)    {        switch (c)        {            case '(' or '[' or '{':                stack.Push(c);                break;            case ')' or ']' or '}':                char expected = c == ')' ? '(' : c == ']' ? '[' : '{';                if (!stack.TryPop(out char top) || top != expected)                    return false;             // nothing open, or wrong partner                break;        }    }    return stack.Count == 0;                  // anything left was never closed} Console.WriteLine(IsBalanced("if (a[i] > 0) { f(x); }"));Console.WriteLine(IsBalanced("Math.Max(a[0], b[1)]"));
Output
True
False

Undo and redo with two stacks

UndoRedo.cs
var undo = new Stack<string>();var redo = new Stack<string>(); void Do(string action)  { undo.Push(action); redo.Clear(); Console.WriteLine($"do   {action}"); }void Undo()             { if (undo.TryPop(out var a)) { redo.Push(a); Console.WriteLine($"undo {a}"); } }void Redo()             { if (redo.TryPop(out var a)) { undo.Push(a); Console.WriteLine($"redo {a}"); } } Do("move beam");Do("rotate column");Undo();Undo();Redo();
Output
do   move beam
do   rotate column
undo rotate column
undo move beam
redo move beam

Evaluating expressions

Calculators and compilers often turn (3 + 4) * 2 into postfix form (3 4 + 2 *), where each operator comes after its two operands. Postfix needs no brackets and is evaluated with one stack: push numbers; for an operator, pop two numbers, apply it, push the result.

Postfix.cs
static double EvalPostfix(string expr){    var stack = new Stack<double>();    foreach (var token in expr.Split(' ', StringSplitOptions.RemoveEmptyEntries))    {        if (double.TryParse(token, out double number)) { stack.Push(number); continue; }         double right = stack.Pop(), left = stack.Pop();   // note the order!        stack.Push(token switch        {            "+" => left + right,            "-" => left - right,            "*" => left * right,            "/" => left / right,            _ => throw new FormatException($"Unknown operator {token}")        });    }    return stack.Pop();} Console.WriteLine(EvalPostfix("3 4 + 2 *"));      // (3 + 4) * 2Console.WriteLine(EvalPostfix("10 2 8 * + 3 -")); // 10 + 2 * 8 - 3
Output
14
23

Pattern: the monotonic stack

A powerful interview pattern: for each element, find the next greater element to its right. The naive way checks every pair (O(n²)). With a stack of indexes still waiting for an answer, each index is pushed and popped once: O(n).

NextGreater.cs
static int[] NextGreater(int[] a){    var result = new int[a.Length];    Array.Fill(result, -1);    var waiting = new Stack<int>();             // indexes, values decreasing from bottom to top     for (int i = 0; i < a.Length; i++)    {        while (waiting.Count > 0 && a[waiting.Peek()] < a[i])            result[waiting.Pop()] = a[i];       // a[i] is the answer for everything smaller        waiting.Push(i);    }    return result;                               // still waiting → no greater element (-1)} Console.WriteLine(string.Join(", ", NextGreater([2, 1, 5, 3, 6])));
Output
5, 5, 6, 6, -1
Quick check

Push 1, push 2, push 3, pop, push 4, pop, pop. What is left on the stack?

Quick check

Why is (] not balanced, even though it has one opening and one closing bracket?

Practice

Remove adjacent pairs of equal letters repeatedly until none are left. Example: "abbaca" → remove bb → "aaca" → remove aa → "ca". Solve it in one O(n) pass with a stack.

Show a hint

For each letter: if it equals the top of the stack, pop (the pair cancels); otherwise push it. The stack holds the answer, bottom to top.

Show the solution
Solution.cs
static string RemoveDuplicates(string s){    var stack = new Stack<char>();    foreach (char c in s)    {        if (stack.Count > 0 && stack.Peek() == c) stack.Pop();        else stack.Push(c);    }    var chars = stack.ToArray();      // ToArray returns top first    Array.Reverse(chars);    return new string(chars);} Console.WriteLine(RemoveDuplicates("abbaca"));Console.WriteLine(RemoveDuplicates("azxxzy"));
Output
ca
ay

Remember

  • A stack is LIFO: push and pop at the top, both O(1).
  • It is just an array (or List) where you only use the end; .NET provides Stack<T>.
  • Use a stack when the most recent unfinished thing must be handled first: brackets, undo, expressions, the call stack.
  • A monotonic stack turns “next greater element” problems from O(n²) into O(n).
0 of 50 lessons completed