Follow a path, then backtrack
Choose Structure Type in the visualizer, then press Start Search and Step to see one path grow and retreat. Auto completes the traversal; Reset State starts again. A different neighbour order can produce a different valid DFS order.
A graph implementation
def dfs(graph, start):
seen = set()
order = []
def visit(node):
seen.add(node)
order.append(node)
for neighbour in graph[node]:
if neighbour not in seen:
visit(neighbour)
visit(start)
return order
The recursive calls form an implicit stack. A node is marked when first reached, which prevents a cycle from repeating the traversal.
What DFS is useful for
DFS can explore connected components, detect cycles, produce a topological order in a directed acyclic graph, and support maze or state-space search. It does not guarantee the shortest path. For shortest paths by edge count in an unweighted graph, use breadth-first search.
With an adjacency-list graph, DFS takes O(V + E) time and O(V) extra space for visited nodes and the call stack. Recursive DFS is concise, but a very deep graph can exceed the language’s call-stack limit; an explicit stack avoids that recursion limit.
Common mistakes with Depth First Search
- Skipping the visited set: cycles can send the search around forever.
- Marking only after exploring neighbours: a node may be pushed repeatedly; mark it when discovered.
- Assuming one fixed traversal order: it depends on the order in which neighbours are listed.
- Using DFS for shortest paths: depth-first order does not minimize distance.