Module A-4·16 min read

Depth-first traversal, recursive and iterative, and the visited-set discipline that prevents infinite loops on cyclic graphs.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

Module A-4 — Graph Traversal: Depth-First Search (DFS)

What this module covers: Module P-4's tree traversals assumed a tree — no cycles, exactly one path to any node. A general graph (Module P-6) has neither guarantee, which means traversing one safely requires one new piece of bookkeeping: a record of what's already been visited. This module covers depth-first search, both recursive (Module P-1) and iterative (Module F-6's explicit stack), and two classic applications — counting connected regions in a grid, and deep-copying a graph that might contain cycles.


Why Graphs Need a Visited Set

A tree traversal (Module P-4) never revisits a node, because a tree has no cycles — there's exactly one path from the root to any node, so recursing into children can never loop back on itself. A graph has no such guarantee: two nodes can point to each other, or a longer cycle can exist (A → B → C → A). Traversing a graph without tracking what's already been visited risks an infinite loop, walking the same cycle forever.

typescript

Note the shape: check-and-mark visited, process the node, then recurse into each neighbor — this is exactly Module P-4's preorder pattern (root, then children), just generalized from "two fixed children" to "however many neighbors this node happens to have," and with the visited set added specifically to handle the cycles a tree never had to worry about.


Iterative DFS: The Explicit Stack, Made Visible

Recursive DFS relies on the call stack (Module P-1) to remember which nodes still need their remaining neighbors explored. The iterative version makes that bookkeeping explicit, using Module F-6's stack directly:

typescript

This is the same trade Module P-4 already made explicit for tree traversal: the stack here holds exactly what the recursive call stack was managing implicitly — "which nodes are still waiting to have their neighbors explored." One subtlety worth naming: nodes can be pushed onto the stack more than once (a node might be reachable via two different neighbors before either has been processed) — the if (visited.has(node)) continue check at the top of the loop is what safely discards those duplicate entries when they're eventually popped, rather than reprocessing an already-visited node.


Application: Number of Islands (DFS on a Grid)

A 2D grid of land (1) and water (0) — count the number of distinct islands, where an island is a group of land cells connected horizontally or vertically. A grid is an implicit graph: each cell is a node, and its up/down/left/right neighbors are its edges (Module A-9 covers this grid-as-graph framing in full).

typescript

Every time an unvisited land cell is found during the scan, it must belong to a brand-new island — so the count increments once, and exploreIsland marks every cell reachable from it (in any of the four directions) as visited, ensuring none of them triggers a second, incorrect increment later in the scan. This is precisely Module A-3's connected-components question — "how many separate connected groups exist" — answered here by direct DFS traversal rather than Union-Find's incremental tracking. Both are valid tools for the same underlying question; DFS/BFS suit a one-time count over a static structure, while Union-Find suits a structure that's still being built up edge by edge, needing "are these connected yet" answered incrementally as each edge arrives.

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.