Home/Pathfinding/Breadth-first search
Search algorithmsCTRL K

Breadth-first search

· breadth-first · rings from the start
/pathfinding/breadth-first-search
EXPANDED
0
closed cells
QUEUE
1
waiting in the queue
ENQUEUED
0
cells added to the queue
PATH
—
length once the goal is reached
WALLS
28%
of 880 cells blocked
closedopencurrentpathstart / goal
44×20 · 28% walls · seed 7 · 1134 steps
step 0 / 1133
Walls28
bfs.ts
1
function bfs(grid: Grid, start: Cell, goal: Cell) {
2
  const queue: Cell[] = [start];
3
  const distance = new Map([[start, 0]]), parent = new Map();
4
  while (queue.length > 0) {
5
    const current = queue.shift()!; // oldest first
6
    if (current === goal) return rebuild(parent, current);
7
    for (const neighbor of neighbors(grid, current)) {
8
      if (distance.has(neighbor)) continue;
9
      distance.set(neighbor, distance.get(current)! + 1);
10
      parent.set(neighbor, current);
11
      queue.push(neighbor);
12
    }
13
  }
14
  return null;
15
}
CURRENT STEP
line 2

Start at (12, 1), goal at (5, 42). The open set holds only the start.

// how it works

Understanding Breadth-first search

BFS · the flood fill that finds the shortest path
01

The idea

Breadth-first search explores the grid in rings: every cell at distance 1 from the start, then every cell at distance 2, and so on. It keeps a queue of open cells, always takes the oldest one, and enqueues its unvisited neighbours behind everything already waiting.

Because cells are reached in order of distance, the first time BFS pops the goal it has found a shortest path, as long as every step costs the same. That is its whole guarantee, and also its weakness: it floods evenly in every direction and never looks at where the goal is.

02

The four stages

1
dequeuethe oldest open cell
2
checkis it the goal? then rebuild
3
enqueueunvisited neighbours join the back
4
pathfollow parents back to start
03

Complexity

best
O(d)goal next to the start
average
O(V + E)every cell and edge once
worst
O(V + E)goal unreachable: the whole grid floods
space
O(V)queue plus the parent map
04

Versus its siblings

CELLS EXPANDED · 44×20 MAZE
bfs
612
dijkstra
604
greedy
96
a*
188
jps
41
same maze, same start and goal · BFS visits almost everything
05

Pseudocode

BFS(start, goal)
  queue ← [start]; dist[start] ← 0
  while queue not empty
    current ← dequeue the oldest
    if current = goal: return path via parent
    for each neighbour of current not yet seen
      dist[neighbour] ← dist[current] + 1; parent[neighbour] ← current; enqueue neighbour
06

When to use

Unweighted graphs where every step costs the same: grids, mazes, social hops, word ladders.
When you need all shortest distances from one source, not just one path: BFS labels every cell with its distance.
07

Pitfalls

Weights break it: a cheap long detour beats an expensive short one, and BFS cannot tell. Use Dijkstra.
It expands in every direction, so on a big map with a far goal it visits far more cells than A*.
Marking cells visited when they are popped instead of when they are enqueued duplicates work; mark on enqueue.
08

History

Konrad Zuse described breadth-first search in his 1945 thesis on Plankalkül, which was not published until 1972. Edward Moore rediscovered it in 1959 to find the shortest route through a maze, and C. Y. Lee used it in 1961 for routing wires on circuit boards, the maze router still used in chip design.

Back to Pathfinding