data structures algorithms25 min

Stacks

Last-In-First-Out data structure for tracking state

0/9Not Started

Why This Matters

Every time you press undo, your editor pops the last action off a stack. Every time a function calls another function, the runtime pushes a frame onto the call stack. Stacks are everywhere in computing, and their simplicity is their power: you can only add to the top and remove from the top.

This Last-In-First-Out constraint makes stacks ideal for tracking nested state, reversing sequences, and solving problems where the most recent item matters most. Once you recognize the stack pattern, you will see it in compilers, browsers, operating systems, and everyday algorithms.

Define Terms

Visual Model

A
pushed=1st
B
pushed=2nd
C
pushed=3rd
D
pushed=4th (top)
Call Stack

The full process at a glance. Click Start tour to walk through each step.

A stack: Last In, First Out (LIFO). Push adds to the top, pop removes from the top. Both O(1).

Code Example

Code
// Stack implementation using an array
class Stack {
  constructor() {
    this.items = [];
  }

  push(value) {
    this.items.push(value);
  }

  pop() {
    if (this.isEmpty()) throw new Error("Stack underflow");
    return this.items.pop();
  }

  peek() {
    if (this.isEmpty()) throw new Error("Stack is empty");
    return this.items[this.items.length - 1];
  }

  isEmpty() {
    return this.items.length === 0;
  }

  get size() {
    return this.items.length;
  }
}

// Using a stack
const stack = new Stack();
stack.push("A");
stack.push("B");
stack.push("C");
console.log(stack.peek());  // "C"
console.log(stack.pop());   // "C"
console.log(stack.pop());   // "B"
console.log(stack.size);    // 1

// Practical example: matching parentheses
function isBalanced(str) {
  const stack = new Stack();
  const pairs = { ")": "(", "]": "[", "}": "{" };
  for (const ch of str) {
    if ("([{".includes(ch)) {
      stack.push(ch);
    } else if (")]}".includes(ch)) {
      if (stack.isEmpty() || stack.pop() !== pairs[ch]) {
        return false;
      }
    }
  }
  return stack.isEmpty();
}

console.log(isBalanced("([]){}"));  // true
console.log(isBalanced("([)]"));    // false
console.log(isBalanced("((("));     // false

Interactive Experiment

Try these exercises:

  • Create a stack, push 5 items, then pop them all. Notice the reverse order.
  • Use a stack to reverse a string: push each character, then pop them all into a new string.
  • Trace through the call stack when function a() { b(); } and function b() { c(); } execute.
  • Try calling pop() on an empty stack. What error do you get?
  • Test the parentheses matcher with: "({[]})", "((())", and "}{)".

Quick Quiz

Coding Challenge

Balanced Brackets Checker

Write a function called `isBalanced` that takes a string containing brackets and returns true if all brackets are properly balanced and nested, false otherwise. Handle three types of brackets: (), [], and {}. Non-bracket characters should be ignored.

Loading editor...

Real-World Usage

Stacks power many critical systems:

  • The call stack: Every running program uses a stack to track function calls. When a function returns, its frame is popped off.
  • Undo/redo: Text editors push each action onto an undo stack. Pressing undo pops the last action and pushes it onto a redo stack.
  • Browser back button: Visited pages are pushed onto a history stack. Going back pops the current page.
  • Expression parsing: Compilers use stacks to evaluate mathematical expressions and validate syntax.
  • Depth-first search: DFS algorithms use a stack (explicitly or via recursion) to explore graph paths.

Connections