Coding Patterns
DFS: iterative vs recursive — when should you use each?
Recursive DFS is simple and natural for trees and small-to-medium depth problems. Iterative DFS uses an explicit stack, avoids call-stack overflow, and gives more control for very deep graphs or production-style traversal.
The Short Answer
Recursive DFS is usually easier to write and easier to read.
Iterative DFS uses your own explicit stack. It is better when the graph or tree may be very deep, when recursion depth is risky, or when you want more control over traversal state.
The Real Problem
DFS is naturally recursive because each node says: “visit me, then visit my children or neighbors.”
void dfs(Node node) {
if (node == null) {
return;
}
visit(node);
for (Node neighbor : node.neighbors) {
dfs(neighbor);
}
}This is beautiful. But every recursive call adds another frame to the call stack.
Mental Model
Recursive DFS
Iterative DFS
Recursive DFS Example
Recursive DFS is great when the depth is reasonable and the recursive structure makes the solution easier to understand.
void dfs(Node node, Set<Node> visited) {
if (node == null || visited.contains(node)) {
return;
}
visited.add(node);
visit(node);
for (Node neighbor : node.neighbors) {
dfs(neighbor, visited);
}
}This is often perfect for interview problems like trees, islands, connected components, and backtracking.
Iterative DFS Example
Iterative DFS replaces recursive calls with an explicit stack.
void dfsIterative(Node start) {
Deque<Node> stack = new ArrayDeque<>();
Set<Node> visited = new HashSet<>();
stack.push(start);
while (!stack.isEmpty()) {
Node node = stack.pop();
if (visited.contains(node)) {
continue;
}
visited.add(node);
visit(node);
for (Node neighbor : node.neighbors) {
if (!visited.contains(neighbor)) {
stack.push(neighbor);
}
}
}
}In Java, prefer Deque with ArrayDeque for stack-style operations instead of the older Stack class.
When Recursive DFS Is Usually Better
- The tree or graph depth is small or controlled.
- The recursive structure makes the code much clearer.
- You are doing backtracking.
- You need pre-order, in-order, or post-order tree traversal.
- The interview favors clarity over production hardening.
When Iterative DFS Is Required or Safer
Iterative DFS becomes important when recursion depth may be too large.
- A graph can have hundreds of thousands of nodes in one chain.
- A tree is extremely skewed, like a linked list.
- The input comes from users or external data and depth is unknown.
- You are writing production code that must avoid stack overflow.
- You need custom control over traversal state.
Example: Recursive DFS Can Fail on a Deep Chain
Imagine a graph that is basically one long chain:
1 -> 2 -> 3 -> 4 -> 5 -> ... -> 1,000,000Recursive DFS would create one method call per node before it can unwind.
Recursive Version
Iterative Version
Important Difference: Traversal Order
Iterative DFS may visit nodes in a different order than recursive DFS unless you push neighbors carefully.
Recursive DFS visits neighbors in the order of the loop:
for (Node neighbor : node.neighbors) {
dfs(neighbor);
}But iterative DFS uses a stack, so the last pushed neighbor is processed first.
// To mimic recursive order,
// push neighbors in reverse order.
List<Node> neighbors = node.neighbors;
for (int i = neighbors.size() - 1; i >= 0; i--) {
stack.push(neighbors.get(i));
}Backtracking Is Easier Recursively
For backtracking problems, recursion is often much easier because the call stack naturally remembers where you are.
path.add(choice);
dfs(nextState);
path.remove(path.size() - 1);You can implement backtracking iteratively, but the code usually becomes more complex because you must manually store extra state.
Real Situations Where Iterative DFS Is Required
Recursive DFS is elegant, but some real-world systems can easily exceed safe recursion depth.
Huge File System Traversal
Large Web Crawlers
Deep Dependency Graphs
Massive Social Graphs
Untrusted User Input
Production Services
In production systems with unknown or potentially massive depth, iterative DFS is frequently the safer engineering choice.
Decision Table
| Situation | Prefer | Why |
|---|---|---|
| Normal binary tree traversal | Recursive | Cleaner and easier to reason about |
| Very deep graph/tree | Iterative | Avoids call-stack overflow |
| Backtracking problems | Recursive | Call stack naturally stores choices |
| Production traversal over unknown depth | Iterative | More robust and controllable |
| Specific visit order required | Either | But iterative DFS must push neighbors carefully |
The Interview-Friendly Explanation
Common Interview Follow-Ups
Can every recursive DFS be written iteratively?
Usually yes for standard traversal, because recursion can be simulated with an explicit stack. But some recursive backtracking solutions become much more awkward iteratively because you must manually store extra state.
When is recursive DFS dangerous?
When the graph or tree can be very deep. A long chain of nodes can create one recursive call per node and overflow the call stack.
Why use Deque instead of Stack in Java?
Deque implementations like ArrayDeque are the preferred modern way to perform stack-style push/pop operations in Java. The legacy Stack class is generally avoided.
Does iterative DFS use less memory?
Not necessarily. Both DFS versions need memory proportional to traversal depth in the worst case. Recursive DFS uses the call stack. Iterative DFS uses an explicit stack.
Why does iterative DFS sometimes produce a different order?
Because a stack is LIFO. If you push neighbors in normal order, the last neighbor is processed first. To mimic recursive order, push neighbors in reverse order.