Go Deep, Then Backtrack
CS205 Data Structures
Use arrow keys or buttons to navigate
Explore as deep as possible, then backtrack
Click any node as source. Watch DFS go deep then backtrack.
Always walk forward, taking the first available turn. When you hit a dead end, backtrack to the last intersection and try a different path.
DFS is driven by a stack (either the call stack via recursion, or an explicit stack). It visits vertices in a deep-first manner, not level-by-level.
Two equivalent approaches — toggle to compare
Recursive DFS uses the program's call stack implicitly. Iterative DFS uses an explicit Stack data structure. Both do the same thing!
Recursive DFS can overflow on deep graphs (100K+ nodes). The iterative version uses heap memory, avoiding this limit.
Code synced with Canvas — watch the recursion tree build
The recursion tree of DFS-Visit calls IS the DFS tree of the graph.
Explicit stack — watch push/pop operations
Replace the Stack with a Queue, and you get BFS! That's the only structural difference.
Iterative DFS may visit in a different order than recursive, because it pushes ALL neighbors at once. Recursive visits one neighbor completely before looking at the next.
7-node graph — watch the stack, visited set, and DFS tree build live
DFS Tree edges shown in green. Current vertex in amber. Backtracking shown in yellow.
Every edge in a directed graph falls into one of four categories
| Edge Type | Goes To | Color |
|---|---|---|
| Tree | Unvisited (WHITE) | GREEN |
| Back | Ancestor (GRAY) → CYCLE! | AMBER |
| Forward | Descendant (BLACK, d[u]| BLUE | |
| Cross | Neither (BLACK, d[u]>d[v]) | PURPLE |
In undirected graphs, only tree edges and back edges exist. Forward and cross edges cannot occur.
Back edge = CYCLE. This is the foundation of DFS-based cycle detection.
DFS assigns two timestamps: d[v] (discovery) and f[v] (finish)
For any two vertices u, v: their intervals [d[u],f[u]] and [d[v],f[v]] are either entirely disjoint or one completely contains the other. They never partially overlap — like properly nested parentheses!
Each vertex is a box that opens at d[v] and closes at f[v]. Boxes are completely inside each other or completely separate.
Same graph, different exploration — toggle to compare
| Property | BFS | DFS |
|---|---|---|
| Data structure | Queue (FIFO) | Stack (LIFO) |
| Exploration | Level by level | Deep first |
| Shortest path? | Yes (unweighted) | No |
| Cycle detection | Possible | Natural |
| Topological sort | No | Yes |
| Time | O(V+E) | O(V+E) |
WHITE → GRAY → BLACK vertex states determine edge types
Edge to a GRAY vertex = ancestor still being processed = CYCLE!
Toggle directed (3-color) vs undirected (parent-check)
Every undirected edge appears twice (u-v and v-u). Exclude the parent edge when checking for back edges.
Linear ordering where u comes before v for every edge u → v
Topological sort = reverse of DFS finish order. When a vertex finishes (all descendants explored), prepend it to the result.
Only works on DAGs (Directed Acyclic Graphs). If there's a cycle, no valid topological order exists!
Each DFS call from the outer loop discovers one full component
Number of outer-loop DFS calls = number of connected components.
Kosaraju's Algorithm: DFS → Reverse → DFS again
SCCs are "islands" where you can travel between any two cities. Kosaraju finds them by looking at the graph forwards AND backwards.
DFS creates long winding corridors — perfect for mazes
Start at a cell, pick a random unvisited neighbor, remove the wall between them. When stuck, backtrack. This creates a "perfect maze" — exactly one path between any two cells.
DFS naturally backtracks at dead ends, making it ideal for maze solving. It finds a path (not necessarily shortest — use BFS for that).
O(V + E) time, O(V) space — same as BFS
| Representation | DFS Time | Space |
|---|---|---|
| Adjacency List | O(V + E) | O(V) |
| Adjacency Matrix | O(V²) | O(V) |
Each vertex visited once (O(V)). Each edge checked once per direction (O(E)). Total = O(V + E).
Worst case: path graph → stack depth = V. This can cause stack overflow with recursion on deep graphs!
Given this graph and source A (recursive DFS, alphabetical neighbors), what's the visit order?
Undirected graph. Neighbors in alphabetical order. Source = A.
Type the DFS visit order (comma-separated):
This iterative DFS has a subtle bug — can you find it?
What's wrong with this code?
Check if v not in visited before pushing, OR check if u not in visited after popping (and skip if already visited). Without either guard, cycles cause infinite loops!
Pick the best algorithm for each scenario
1. Find if there's a circular dependency in a build system (DAG check).
2. Find the minimum number of hops between two routers in a network.
3. Determine a valid course schedule that respects all prerequisites.
4. Count the number of connected components in an undirected graph.
Everything you need to know about DFS
| Property | DFS | BFS |
|---|---|---|
| Data structure | Stack | Queue |
| Shortest path? | No | Yes |
| Topological sort? | Yes | No |
| Time | O(V+E) | O(V+E) |
| Space | O(V) | O(V) |
3 questions — check your answers when ready
Q1: What does a back edge in DFS indicate?
Q2: How do you get topological sort from DFS?
Q3: What color means "in progress" in 3-color DFS?
Step through DFS on this directed graph, track d[v] and f[v]
What does this Java DFS code print?
What is the visit order (order list)?
What is the finish order (finish list)?