Trees and Graphs
Graphs, BFS, and DFS
Nodes, edges, and the two ways to explore them
Model anything as dots and lines, store it two ways, and explore it with two loops that differ by a single word: queue or stack.
Friend networks, road maps, web links, the dependency tree of your build - they are all the same shape: things and the connections between them. That shape is a graph, and two tiny algorithms - BFS and DFS - are enough to explore any of them. The whole difference between the two is whether you remember where to go next with a queue or a stack.
What a graph is
Two ways to store the same graph
Before you can traverse a graph you have to represent it in memory. There are two standard choices, and the demo below lets you flip the same seven-node graph between them. The trade-off is space versus edge-lookup speed:
| Adjacency list | Adjacency matrix | |
|---|---|---|
| Space | O(V + E) | O(V²) |
| "Is there an edge u-v?" | O(deg u) | O(1) |
| List a node's neighbors | O(deg u) | O(V) |
| Best when the graph is… | sparse (few edges) | dense / needs fast edge tests |
Traverse it: BFS and DFS
Both traversals grow a frontier of discovered-but-not-yet-visited nodes. Press BFS or DFS, then step (or hit Play). Watch the frontier panel: BFS keeps it in a queue and fans out level by level; DFS keeps it in a stack and dives deep down one branch. Flip the representation to see which row the algorithm reads to find a node's neighbors.
Queue · FIFO: take from the front, add to the back
Visit order
Start at A: enqueue it and mark it discovered. We always dequeue from the front of the queue.
Each node stores only its own neighbors → O(V+E) space. The highlighted row is the one the traversal reads right now.
The queue vs. the stack is the whole trick
The matrix, the handshake, and shortest paths
An adjacency matrix is an matrix with
Replace the s with weights, , and you have a weighted adjacency matrix. It costs space even when edges are rare; an adjacency list costs only . Both let a traversal touch every vertex once and every edge once, so BFS and DFS run in time - a consequence of the handshake lemma, . And because BFS drains its frontier first-in-first-out, it reaches every vertex by a fewest-edge path: on an unweighted graph it computes shortest paths for free.
The code is almost identical
Here is the punchline. BFS and DFS are the same loop; the only real difference is one call - popleft() (take from the front, a queue) versus pop() (take from the back, a stack). Everything else, including the visited set that tames cycles, is shared.
from collections import deque
def traverse(graph, start, mode="bfs"):
frontier = deque([start]) # bfs: use as a queue · dfs: use as a stack
seen = {start} # visited set: never enqueue a node twice
order = []
while frontier:
node = frontier.popleft() if mode == "bfs" else frontier.pop()
order.append(node) # "visit" the node
nbrs = graph[node] if mode == "bfs" else reversed(graph[node])
for nb in nbrs: # explore neighbors (reversed for dfs = recursion order)
if nb not in seen: # skip seen nodes -> no infinite loop on cycles
seen.add(nb)
frontier.append(nb)
return order # bfs -> level order · dfs -> deep-firstDon't forget the visited set
seen check and any graph with a cycle sends the traversal into an infinite loop - it will keep re-discovering nodes it already reached. The visited set is also what turns DFS into a tool for cycle detection and lets you count connected components: start a fresh traversal from every still-unvisited node, and the number of restarts is the number of components.Check yourself
Which frontier structure makes a graph traversal explore level by level?
For a large, sparse graph, why favor an adjacency list over a matrix?
Recall: which structure does each traversal use, and what is each one good at?
Tie the frontier structure to what each traversal buys you. Try to state it, then check.
Lock it in
- A graph is just vertices and edges; edges may be directed and weighted.
- Adjacency list is O(V+E) space; adjacency matrix is O(V²) but O(1) edge tests.
- BFS (queue, FIFO) fans out level by level; DFS (stack, LIFO) dives deep.
- The visited set tames cycles and powers cycle detection and connected components.
Primary source
Ask your teacher