Skip to content

Expert · Algorithms, data structures and testing · topic 47 of 50 · 30 min

Stacks and queues

Explanation

A stack is a pile where the last item added is the first one taken out (LIFO); a Python list with append() and pop() works as a stack. A queue is a line where the first item added is the first one out (FIFO); use collections.deque for it. For "most urgent first", the heapq module gives you a priority queue.

A data structure is a way of organising data so that certain actions are fast. You already know lists, dicts and sets. Stacks and queues are simpler ideas built on top of them, and they are behind undo buttons, browser history, print queues, ticket counters and task schedulers.

Think of it like this: A stack is a pile of plates at a wedding buffet: you put a clean plate on top and the next guest takes the top plate. Last in, first out. A queue is the line at a railway ticket counter: the person who came first is served first. First in, first out.

A stack with a list

LIFO stands for Last In, First Out. Adding to a stack is called push; removing the top item is called pop. A Python list does both at its end in O(1): append() pushes and pop() pops. my_list[-1] lets you look at the top without removing it (often called peek).

python
history = []                    # an empty stack
history.append("home")          # push
history.append("search")
history.append("product page")
print(history[-1])              # peek: product page
print(history.pop())            # back button: product page
print(history.pop())            # search
print(history)                  # ['home']
Browser back buttons and undo features work exactly like this.

Checking balanced brackets with a stack

  1. Go through the text one character at a time.
  2. When you see an opening bracket ( [ or {, push it onto the stack.
  3. When you see a closing bracket, the top of the stack must be its matching opener. If the stack is empty or the top does not match, the text is not balanced.
  4. At the end, the stack must be empty; leftover openers mean something was never closed.
python
def is_balanced(text):
    pairs = {")": "(", "]": "[", "}": "{"}
    stack = []
    for ch in text:
        if ch in "([{":
            stack.append(ch)
        elif ch in pairs:
            if not stack or stack.pop() != pairs[ch]:
                return False
    return not stack

print(is_balanced("total = (price * (1 + gst[0]))"))   # True
print(is_balanced("print((x)"))                         # False
Code editors and compilers use this idea to spot a missing bracket.

A queue with collections.deque

FIFO stands for First In, First Out. A deque (say "deck", short for double-ended queue) from the collections module adds and removes at both ends in O(1). Use append() to join the back of the queue and popleft() to serve the front.

python
from collections import deque

counter = deque()
counter.append("Asha")      # joins the line
counter.append("Bilal")
counter.append("Chen")
print(counter.popleft())    # Asha is served first
print(len(counter), "still waiting:", list(counter))
Join at the back with append, leave from the front with popleft.
Careful: Do not use list.pop(0) as a queue for big data. Removing the first item of a list makes Python shift every other item one place to the left, which is O(n) per pop. Over n pops that becomes O(n^2). deque.popleft() is O(1).
python
import time
from collections import deque

n = 20_000
items = list(range(n))
start = time.perf_counter()
while items:
    items.pop(0)
list_ms = (time.perf_counter() - start) * 1000

line = deque(range(n))
start = time.perf_counter()
while line:
    line.popleft()
deque_ms = (time.perf_counter() - start) * 1000

print("list.pop(0):", round(list_ms, 1), "ms   deque.popleft():", round(deque_ms, 1), "ms")
The difference grows quickly as n grows.

Priority queues with heapq

Sometimes the most important item should come out first, not the oldest. That is a priority queue. The heapq module keeps a list arranged as a heap, a tree-like order where the smallest item is always at position 0. heappush and heappop each take O(log n).

python
import heapq

emergency = []
heapq.heappush(emergency, (3, "sprained ankle"))
heapq.heappush(emergency, (1, "heart attack"))
heapq.heappush(emergency, (2, "high fever"))

while emergency:
    priority, case = heapq.heappop(emergency)
    print(priority, case)          # 1 first, then 2, then 3
Store (priority, item) tuples: the smallest number comes out first.

The idea of a linked list

A linked list stores items in separate little boxes called nodes. Each node holds a value and a pointer (a reference) to the next node, like a treasure hunt where each clue tells you where the next clue is. Adding or removing at the front is fast, because you only change one pointer, but reaching the 500th item means walking through 499 nodes. Python's deque is built from linked blocks for this reason.

StructureOrderPython toolReal use
StackLIFOlist: append / popUndo, back button, bracket checking
QueueFIFOcollections.deque: append / popleftTicket counter, print jobs, order processing
Priority queueSmallest firstheapq: heappush / heappopHospital triage, task schedulers, shortest routes
Tip: In interviews, when a problem says "the most recent", think stack. When it says "in the order they arrived", think queue. When it says "the smallest, cheapest or most urgent next", think heap.

Watch the lesson

Stacks and queues · 1/7

Stacks and queues

In this lesson you will learn two simple but powerful data structures: stacks and queues.

Prefer a video by a teacher? Find free videos on “python stacks queues deque heapq tutorial” on YouTube ↗

In real life: Undo in a photo editing app and the order queue of a cloud kitchen

A photo editing app records every change (crop, brighten, add a filter) on a stack; pressing undo pops the last change and reverses it. In the same company, a cloud kitchen receives orders from several delivery apps and cooks them in the order they arrived, using a queue, while VIP or delayed orders jump ahead using a priority queue.

python
edits = []
for action in ["crop", "brighten", "add filter"]:
    edits.append(action)
print("Undo:", edits.pop())
print("Undo:", edits.pop())
print("Remaining edits:", edits)
Each undo removes the most recent edit first.

Practice (0/3 done)

Task 1 · Code · Python

Write is_balanced(text) that returns True if every bracket ( [ { in text is closed by the matching ) ] } in the right order, and False otherwise. Other characters are ignored. Use a list as a stack.

Task 2 · Code · Python

Write a class TicketCounter that uses a collections.deque stored in self.queue. join(name) adds a person at the back. serve() removes and returns the person at the front, or None if nobody is waiting. waiting() returns how many people are in the line.

Task 3 · Code · Python

Write next_patients(patients, k). patients is a list of (priority, name) tuples in arrival order; a smaller priority number is more urgent. Return a list of the names of the k most urgent patients, most urgent first. If two have the same priority, the one who arrived first goes first. Use heapq.

Quick quiz

Question 1

1.Which order does a stack follow?

Question 2

2.Which is the best tool for a large FIFO queue in Python?

Question 3

3.s = []; s.append(1); s.append(2); s.append(3); s.pop(); What does s.pop() return now?

Question 4

4.What does heapq.heappop(h) return?

Question 5

5.In a linked list, why is reaching the 500th item slow?

Read more (free)

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

← Previous: Recursion and sorting algorithms