◐ ai-teacher

🧩 Data Structures & Algorithms · Chapter 6

Stacks

Undo in your editor, the back button in your browser, and the way your program remembers where to return after a function call are all the same tiny structure: last in, first out.

Study this lesson free in the app →

The basics

A stack is a collection where you only touch the top: you push an item onto it, and pop the most recently pushed item off. Last in, first out — LIFO.

The problem it solves: many tasks need to remember things and then deal with them in reverse order — the most recent unfinished thing first. Undo reverses your latest edit. A closing bracket must match the most recent unmatched opening bracket. When a function finishes, the program returns to the function that called it most recently. A stack gives you exactly that order, with every operation in O(1) time.

The mental model: a pile of plates in a kitchen. You put a clean plate on top, and you take from the top. You never pull from the middle.

Words you must know 5

push(x)
put x on top. O(1).
pop()
remove and return the top. O(1). Popping an empty stack is an error.
peek / top
look at the top without removing it. O(1).
LIFO
last in, first out.
Call stack
the stack your language uses to track active function calls; too-deep recursion overflows it.

In Python, a plain list is a stack: append pushes, pop() pops, lst[-1] peeks. Space is O(n) for n items.

Explained

You type a sentence, bold a word, then delete a paragraph. You press Undo three times.

The paragraph comes back first, then the bold disappears, then the sentence goes. Most recent first, every time.

That order — last in, first out — is a stack, and it's also how your program finds its way back out of every function call it makes.

Plates in a canteen

A canteen keeps clean plates in a spring-loaded stack. The dishwasher puts each clean plate on top; each diner takes the plate on top.

Nobody digs for the plate at the bottom — it's the one that's been waiting longest, and it will be the last one used.

Now imagine a waiter carrying nested trays: a big tray, on it a smaller tray, on that a saucer. To put them away, he must remove the saucer first, then the small tray, then the big one — the reverse of how they were stacked. Brackets in { [ ( ) ] } work the same way: the innermost one opened last must close first.

Precisely

A stack supports:

| Operation | Does | Time | | --- | --- | --- | | push(x) | add x on top | O(1) | | pop() | remove and return the top | O(1) | | peek() | return the top, leave it | O(1) | | is_empty() | any items left? | O(1) |

Space is O(n) for n items. There's no searching or indexing — that's the point: the restriction is what makes every operation constant-time.

Implementations:

collections.deque also works as a stack (append / pop). For multi-threaded producers and consumers, queue.LifoQueue adds locking.

Push, peek, pop

Three pushes build 3, 7, 1 with 1 on top. peek shows 1 but leaves it. pop removes 1. Push 9, then pop takes 9 — the newest — not 7. The last pop removes 7, leaving only 3, the first item in. Every operation touches only the top: O(1).

Brackets as a stack: { [ ( ) ] }

Read { [ ( ) ] } left to right, with 3 = {, 2 = [, 1 = (. Each opener is pushed. Each closer pops — and the popped item is always the most recent unmatched opener, which is exactly the one it must match: ) pops (, ] pops [, } pops {. Empty at the end → balanced.

A monotonic stack: next greater element

def next_greater(nums):
    ans = [-1] * len(nums)
    stack = []                         # indices still waiting for a bigger value
    for i, x in enumerate(nums):
        while stack and nums[stack[-1]] < x:
            ans[stack.pop()] = x       # x is the answer for everyone smaller
        stack.append(i)
    return ans

next_greater([2, 1, 5, 3, 4])          # [5, 5, -1, 4, -1]

The stack always holds values in decreasing order from bottom to top. When a bigger value arrives, it resolves every smaller value waiting on top.

There's a while inside a for, but every index is pushed exactly once and popped at most once — so it's O(n) time, O(n) space, not O(n²). The same shape solves "days until a warmer temperature", "stock span" and "largest rectangle in a histogram".

The stack you didn't create

Every running program has a call stack. Calling a function pushes a frame (its local variables and where to return); returning pops it.

main() → load() → parse() → parse_row()      ← top

When parse_row returns, control goes back to parse — the frame underneath. A crash prints this stack as the traceback.

Recursion pushes one frame per level. Python caps the depth at about 1,000 frames by default (sys.getrecursionlimit()), then raises RecursionError; C and Java crash with a stack overflow. So recursion over a 100,000-node linked list or a very deep tree will fail in Python — the fix is to convert it to a loop with your own stack, which lives on the heap and can grow as large as memory allows.

That's also why depth-first search is usually written with an explicit stack in production code.

Gotchas

Words to know

StackA last-in, first-out collection where items are added and removed only at the top.
LIFOLast in, first out — the most recently added item is the first removed.
Push / pop / peekAdd to the top; remove and return the top; read the top without removing it — all O(1).
Call stackThe runtime stack of active function calls; each call pushes a frame and each return pops it.
Stack overflowRunning out of call-stack space, usually from recursion that is too deep (Python raises RecursionError).
Monotonic stackA stack kept in increasing or decreasing order by popping items that would break the order; solves next-greater problems in O(n).

In two minutes

Test yourself

1. What does LIFO mean for a stack?

  1. The oldest item is removed first
  2. Items are removed in sorted order
  3. The most recently added item is removed first
  4. Items can be removed from either end
Show the answer

The most recently added item is removed first — Last in, first out. Oldest-first is a queue (FIFO); sorted order is a priority queue; both ends is a deque.

2. Using a Python list as a stack, what are the costs of append(x) and pop()?

  1. O(1) and O(1) — both work at the end of the list
  2. O(n) and O(1)
  3. O(1) and O(n)
  4. O(log n) each
Show the answer

O(1) and O(1) — both work at the end of the list — Both operate at the end, where nothing has to shift. (append is amortised O(1) because of occasional resizing.)

3. Starting from an empty stack: push A, push B, pop, push C, push D, pop, pop, pop. In what order are items popped?

  1. A, B, C, D
  2. B, C, D, A
  3. D, C, B, A
  4. B, D, C, A
Show the answer

B, D, C, A — Pop 1 takes B (top of A, B). Then C and D are pushed onto A: pops take D, then C, then A. Each pop takes whatever is newest at that moment.

4. A browser's Back button returns you to the page you visited just before the current one. Which structure fits?

  1. Stack
  2. Queue
  3. Hash set
  4. Sorted array
Show the answer

Stack — The most recently visited page is the first one you go back to — LIFO. A queue would take you to the first page of your session.

5. Evaluate the postfix (Reverse Polish) expression 3 4 + 2 * with a stack: push numbers; for an operator, pop two, apply, push the result.

  1. 11
  2. 14
  3. 10
  4. 24
Show the answer

14 — Push 3, push 4; '+' pops 4 and 3 → push 7; push 2; '*' pops 2 and 7 → 14. Postfix needs no parentheses because the stack enforces the order.

6. Is "([)]" balanced, using the stack algorithm?

  1. Yes — two openers and two closers of each kind
  2. Yes — the stack is empty at the end
  3. No — ')' pops '[' , which doesn't match
  4. No — brackets can't be mixed
Show the answer

No — ')' pops '[' , which doesn't match — After '(' and '[', the top is '['. The ')' must match the most recent opener, and '[' isn't '('. Equal counts aren't enough — order matters, which is why a counter can't solve the mixed-bracket version.

There are 9 questions, 4 puzzles and 5 recall cards for this lesson in the app — the recall cards come back on later days, just before you would forget.

Learn it so it stays. Read it, test yourself, then recall it on two different days. The app schedules that for you, free.

Start this lesson →