BFS
DFS
Graph Traversal
Algorithms
Computer Science

What's the purpose of BFS and DFS?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

BFS and DFS are foundational graph traversal techniques used to visit nodes in different orders. BFS explores by distance layers, while DFS explores deeply along one branch before backtracking. Their purpose is not just traversal, but enabling different classes of graph problems efficiently.

Purpose of BFS

Breadth-First Search uses a queue and visits nodes in order of increasing edge distance from a start node. This makes BFS the standard approach for shortest path by hop count in unweighted graphs.

Typical BFS applications:

  • shortest path in unweighted networks
  • level-order tree traversal
  • minimum-step puzzle solving
  • nearest-match search in grid maps
python
1from collections import deque
2
3def bfs_shortest_path(graph: dict[str, list[str]], start: str, goal: str) -> list[str]:
4    queue = deque([start])
5    parent: dict[str, str | None] = {start: None}
6
7    while queue:
8        node = queue.popleft()
9        if node == goal:
10            break
11        for nxt in graph.get(node, []):
12            if nxt not in parent:
13                parent[nxt] = node
14                queue.append(nxt)
15
16    if goal not in parent:
17        return []
18
19    path = []
20    cur: str | None = goal
21    while cur is not None:
22        path.append(cur)
23        cur = parent[cur]
24
25    return list(reversed(path))

Purpose of DFS

Depth-First Search uses recursion or an explicit stack to follow one branch as far as possible before backtracking. DFS is especially useful for structural analysis and exhaustive exploration.

Typical DFS applications:

  • connected component discovery
  • cycle detection
  • topological sort workflows
  • backtracking and state-space exploration
python
1def dfs_order(graph: dict[str, list[str]], start: str) -> list[str]:
2    visited: set[str] = set()
3    order: list[str] = []
4
5    def visit(node: str) -> None:
6        if node in visited:
7            return
8        visited.add(node)
9        order.append(node)
10        for nxt in graph.get(node, []):
11            visit(nxt)
12
13    visit(start)
14    return order

DFS does not guarantee shortest paths in unweighted graphs, but it is often simpler for dependency and structure problems.

Choosing Between BFS and DFS

Use this practical rule:

  • Need shortest path in unweighted graph: BFS.
  • Need deep structure analysis or exhaustive exploration: DFS.
  • Need layered distance information: BFS.
  • Need recursive decomposition logic: DFS.

Problem objective should decide traversal, not coding preference.

Complexity and Memory Tradeoffs

Both BFS and DFS have O(V + E) time complexity for graph with V vertices and E edges.

Memory profiles differ:

  • BFS stores frontier queues, which can grow large in wide graphs.
  • DFS stores recursion or explicit stack, often smaller on wide levels but risky on deep recursion.

For unknown depth or potentially deep graphs, iterative DFS avoids recursion-depth failures.

python
1def dfs_iterative(graph: dict[int, list[int]], start: int) -> list[int]:
2    stack = [start]
3    visited = set()
4    order = []
5
6    while stack:
7        node = stack.pop()
8        if node in visited:
9            continue
10        visited.add(node)
11        order.append(node)
12        for nxt in reversed(graph.get(node, [])):
13            if nxt not in visited:
14                stack.append(nxt)
15
16    return order

Real-World Usage Patterns

In production systems, BFS and DFS are often combined. For example, DFS may identify connected components, and BFS may then compute shortest distances inside each component. Understanding both gives flexibility in designing performant graph pipelines.

Common Pitfalls

  • Using DFS where shortest unweighted path is required.
  • Forgetting visited tracking and looping forever in cyclic graphs.
  • Assuming BFS memory usage is always small.
  • Using recursive DFS on deep graphs without depth safeguards.
  • Picking traversal style before clarifying the actual objective.

Summary

  • BFS and DFS solve different traversal needs.
  • BFS is best for shortest-hop and level-order tasks.
  • DFS is best for deep structural exploration and backtracking.
  • Both are linear in graph size but have different memory behavior.
  • Select traversal strategy based on problem semantics and graph shape.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.