Pattern GuideBreadth-First Search

Breadth-First Search

"Level by level — the closest nodes first, expanding outward like ripples in a pond."

7 min read Fundamental O(V+E)
01
CORE INTUITION

The Queue: First In, Closest First

šŸ”µ

Why a Queue?

BFS explores nodes in order of their distance from the start. A queue (FIFO) naturally enforces this: we process nodes in the order they were discovered, ensuring we finish one level before moving to the next.

When to use: Shortest path in unweighted graphs, level-order tree traversal, topological ordering, finding connected components.

02
VISUALIZER

Interactive Grid Pathfinder (BFS)

Click empty cells to toggle walls (stone blocks). Watch the queue grow and shrink as BFS searches radially to find the target.
Visited cells are shaded by BFS depth — darker green means closer to the start, so you can see the "rings" expand level by level.

S
🧱
🧱
🧱
🧱
🧱
🧱
🧱
🧱
T

Simulation Status

Click Play or step forward to start.

FIFO QUEUE (Front → Back)Size: 1
0
Delay:400ms
03
THEORY

Queue Node Lifecycle & The Visited Trap

In BFS graph traversal, nodes pass through a strict lifecycle of states. To handle this properly, standard implementations use a visited tracker (like a set or boolean array).

The Three States

  • White (Unvisited): Undiscovered node.
  • Gray (Queued): Added to queue, waiting to be processed.
  • Black (Processed): Popped, neighbors checked.

The Visited Trap

CRITICAL RULE: Always mark a node as visited immediately when pushing it to the queue.

If you wait to mark it visited until it is popped, multiple other nodes will keep pushing the same unvisited neighbor onto the queue, causing exponential redundant operations and heap memory overflows!

04
BLUEPRINTS

Essential BFS Strategies

1. Standard BFS Template

How it Works

  • Pushes start node onto a FIFO queue.
  • Extracts front node, checks neighbors.
  • Uses a visited set to avoid double-processing cycles.
  • Ensures O(V + E) time and space.
bfsTemplate.js
1
function bfs(startNode) {
2
const queue = [startNode];
3
const visited = new Set([startNode]);
4
5
while (queue.length > 0) {
6
const node = queue.shift();
7
// Process node here
8
9
for (const neighbor of node.neighbors) {
10
if (!visited.has(neighbor)) {
11
visited.add(neighbor); // Mark visited IMMEDIATELY when pushed
12
queue.push(neighbor);
13
}
14
}
15
}
16
}

2. Binary Tree Level Order

How it Works

  • Extracts level size before running child iteration.
  • Uses an inner loop to flush one complete level in a single pass.
  • Pushes child nodes (left and right) for subsequent layer processing.
  • Gathers values into horizontal arrays row-by-row.
levelOrder.js
1
function levelOrder(root) {
2
if (!root) return [];
3
const result = [];
4
const queue = [root];
5
6
while (queue.length > 0) {
7
const levelSize = queue.length;
8
const currentLevel = [];
9
10
for (let i = 0; i < levelSize; i++) {
11
const node = queue.shift();
12
currentLevel.push(node.val);
13
14
if (node.left) queue.push(node.left);
15
if (node.right) queue.push(node.right);
16
}
17
result.push(currentLevel);
18
}
19
return result;
20
}

3. Shortest Path on Graph

How it Works

  • Enqueues path coordinates or step sizes alongside node ID.
  • Since BFS explores in absolute radial levels, the first match is guaranteed to be shortest.
  • Guards visited nodes to avoid looping back.
  • Ideal for unweighted graphs (grids, mazes).
shortestPath.js
1
function shortestPath(graph, start, target) {
2
const queue = [start];
3
const visited = new Set([start]);
4
const parentMap = new Map();
5
6
while (queue.length > 0) {
7
const node = queue.shift();
8
if (node === target) {
9
// Reconstruct path
10
const path = [];
11
let curr = target;
12
while (curr !== start) {
13
path.push(curr);
14
curr = parentMap.get(curr);
15
}
16
path.push(start);
17
return path.reverse();
18
}
19
20
for (const neighbor of graph.get(node) || []) {
21
if (!visited.has(neighbor)) {
22
visited.add(neighbor);
23
parentMap.set(neighbor, node);
24
queue.push(neighbor);
25
}
26
}
27
}
28
return []; // Unreachable
29
}
05
BFS vs DFS

When to Use Which

BFS (Queue)

  • Shortest path (unweighted)
  • Level-order traversal
  • Topological sort (Kahn's)
  • Closest target in a grid

DFS (Stack)

  • Path existence (any path)
  • Topological sort (post-order)
  • Cycle detection (directed)
  • Backtracking / combination searches

Memory Footprint: Width vs Depth

Space complexity of search algorithms depends on the shape of the search tree/graph:
• BFS Space Complexity: Bounded by the graph's maximum width (O(W)). For a perfect binary tree, the leaf level contains N/2 nodes, causing a worst-case space footprint of O(N) to hold the active level in the queue.
• DFS Space Complexity: Bounded by the graph's maximum depth (O(H)) because the call stack only retains active ancestors along the current search branch. For a balanced binary tree, the depth is O(log N), which is highly memory efficient!

06
APPLICATIONS

Real-world BFS Systems

1. Web Crawling & Indexing

Problem: Traverse links to discover and index websites.
Core Logic: Search engine crawlers typically use BFS. Starting from popular root URLs, links are parsed and enqueued. Traversing in level-order ensures that sites closer to the root (more popular/linked sites) are indexed first, preventing the crawler from getting stuck in deep, obscure link directories.

2. Peer-to-Peer (P2P) Networks

Problem: Broadcast messages or search files across network peers.
Core Logic: In decentralized networks, search messages are flooded to adjacent peers. BFS ensures the search spreads radially outwards, finding matching files in the closest peers first to minimize network latency.

3. Social Network Connections (Degrees of Separation)

Problem: Identify 1st, 2nd, and 3rd degree connections on platforms like LinkedIn.
Core Logic: We run BFS from the target user. Level 1 retrieves direct friends, Level 2 retrieves friends of friends (2nd degree), and Level 3 retrieves 3rd degree connections.

07
PITFALLS

Common Mistakes

Marking Visited on Pop

Waiting to mark a node visited until it's popped (instead of the moment it's pushed) lets several other queued nodes discover and re-push the same neighbor before it's processed — the queue bloats with duplicates and BFS gets slow.

Array as Queue

array.shift() (JS) or list.pop(0) (Python) is O(N) because every remaining element shifts down an index. On large graphs this silently degrades BFS to O(N²). Use a real queue — collections.deque in Python, an index pointer or linked list in JS.

Forgetting Visited Entirely

Skip the visited set and BFS on any graph with a cycle re-queues the same nodes forever, never terminating. Always track visited — and mark it on push, not on pop.

08
PRACTICE

Ready to Practice?

Shortest Path in Binary MatrixMedium
Rotting OrangesMedium
Word LadderHard

"BFS = queue. Distance order. Closest first."