Graph Traversal: BFS and DFS
[!NOTE] If a Graph is a maze, Traversal is the strategy to explore it. There are two main philosophies: Go Wide (BFS) or Go Deep (DFS).
1. Breadth-First Search (BFS)
Imagine dropping a stone in a pond. The ripples expand outward in perfect circles. That is BFS.
- Strategy: Explore all neighbors at the current depth before moving deeper.
- Data Structure: Queue (FIFO).
- Key Property: Finds the Shortest Path in unweighted graphs.
- Analogy: A contagious virus spreading person-to-person.
2. Depth-First Search (DFS)
Imagine solving a maze. You follow a path until you hit a dead end, then backtrack to the last junction and try a different path. That is DFS.
- Strategy: Go as deep as possible down one branch before backtracking.
- Data Structure: Stack (LIFO) or Recursion.
- Key Property: Good for puzzles, topological sorting, and detecting cycles.
- Analogy: Exploring a cave system.
3. Interactive: Traversal Visualizer
Click the grid to place Obstacles (Walls). Then run BFS or DFS to see how they navigate from Start (Green) to fill the available space.
Visited: 0 | Max Depth: 0
Start
Wall
Visited
Frontier
4. Code Implementation
Breadth-First Search (Queue)
Java
public void bfs(int startNode) {
boolean[] visited = new boolean[V];
Queue<Integer> queue = new LinkedList<>();
visited[startNode] = true;
queue.add(startNode);
while (!queue.isEmpty()) {
int u = queue.poll();
System.out.print(u + " ");
for (int v : adj.get(u)) {
if (!visited[v]) {
visited[v] = true;
queue.add(v);
}
}
}
}
Go
func (g *Graph) BFS(startNode int) {
visited := make(map[int]bool)
queue := []int{startNode}
visited[startNode] = true
for len(queue) > 0 {
u := queue[0]
queue = queue[1:] // Dequeue
fmt.Printf("%d ", u)
for _, v := range g.Adj[u] {
if !visited[v] {
visited[v] = true
queue = append(queue, v) // Enqueue
}
}
}
}
Java
public void dfs(int u, boolean[] visited) {
visited[u] = true;
System.out.print(u + " ");
for (int v : adj.get(u)) {
if (!visited[v]) {
dfs(v, visited);
}
}
}
// Wrapper
public void startDFS(int startNode) {
boolean[] visited = new boolean[V];
dfs(startNode, visited);
}
Go
func (g *Graph) DFS(u int, visited map[int]bool) {
visited[u] = true
fmt.Printf("%d ", u)
for _, v := range g.Adj[u] {
if !visited[v] {
g.DFS(v, visited)
}
}
}
// Usage: g.DFS(0, make(map[int]bool))