What is the difference between a queue and a stack?
Updated Feb 20, 2026
Short answer
A queue is FIFO — the first element added is the first removed, like a checkout line. A stack is LIFO — the last added is the first removed, like a pile of plates. Both offer O(1) insertion and removal; the difference is purely which end you remove from, and that single choice determines which problems each solves.
Deep explanation
Queue (FIFO) Stack (LIFO)enqueue -> [A][B][C] -> dequeue push/pop ^oldest first [C] <- last in, first out [B] [A]| Queue | Stack | |
|---|---|---|
| Add | enqueue (back) | push (top) |
| Remove | dequeue (front) | pop (top) |
| Order | oldest first | newest first |
| Natural traversal | BFS | DFS |
Where a queue is the right shape: anything where fairness or arrival order matters. Task and print queues, message brokers, BFS in a graph, request buffering, rate limiting.
Where a stack is: anything where you must return to where you were. Function call frames, undo history, expression evaluation, backtracking, DFS, matching brackets.
The connection to traversal is worth internalising, because BFS and DFS are the same algorithm with a different container — swap the queue for a stack and level-order becomes depth-first. That equivalence is a common interview follow-up.
Implementation note. A stack maps cleanly onto a dynamic array: push and pop both act on the end, which is O(1) amortised. A queue does not — removing from the front of an array shifts every remaining element, making it O(n). Use a linked list, a circular buffer, or a purpose-built structure such as Python's collections.deque.
Real-world example
The same traversal, two containers, two behaviours:
from collections import deque
def traverse(graph, start, use_stack=False): pending = deque([start]) seen, order = {start}, [] while pending: node = pending.pop() if use_stack else pending.popleft() order.append(node) for nbr in graph[node]: if nbr not in seen: seen.add(nbr) pending.append(nbr) return orderpopleft() gives FIFO and produces breadth-first order; pop() gives LIFO and produces depth-first. One line separates finding the shortest path from exhausting one branch at a time.
Common mistakes
- - Implementing a queue on a plain list and using `list.pop(0)`, which is O(n) and turns a linear loop quadratic.
- - Mixing the two mental models — dequeuing from the back or popping from the front — and silently getting the wrong traversal order.
- - Assuming a queue is always the fair choice
- a priority queue is a different structure that ignores arrival order entirely.
- - Forgetting to guard against removing from an empty structure, which throws rather than returning a sentinel in most languages.
- - Using a stack where recursion depth would overflow, without realising an explicit stack is exactly the fix.
Follow-up questions
- Why is `list.pop(0)` a poor way to implement a queue?
- What is a deque and when is it useful?
- How does a priority queue differ from an ordinary queue?
- Why does swapping a queue for a stack turn BFS into DFS?