BeeTool.Dev - Essential Tools for developers

Stories.Tool Tabs VaultPersonal Documents
Super Debugging Context
BeeTool.Dev

Essential tools, knowledge, and playgrounds for developers.

Explore

  • Stories
  • Personal Documents
  • Features
  • Algorithms Playground

Tool Tabs

  • JSON Compare
  • SQL Formatter
  • Text Diff
  • All tools →

Learn

  • Sorting algorithms
  • Searching algorithms
  • Algorithm Race Mode
© 2024 – 2026 BeeTool.DevPrivacy policy
← Algorithms Playground
Searching · Intermediate

Breadth-First Search (BFS)

Explore a graph in expanding rings from the start — the first time you reach a node is provably the shortest unweighted path to it.

AverageO(V + E)StructureGraphNeeds sortedNoComparisonYes
1074196155889363343579
Must remember

Queue + visited set: explore in rings, mark on enqueue, first arrival = shortest unweighted path.

Time O(V + E) · Space O(V)

Hands on Interactive visualization

Target
86
Drag nodes to rearrange
6154894713169685316867887
Frontier
empty
visited 0 · depth 0
0/0Ready — press play
Speed
Step 0 / 0
Comparisons
0
Swaps
0
Reads
0
Writes
0
Elapsed
0.0s
Frames
0
Depth
0 / 0
Aux memory
0 B

Implementation Code

export function bfs(
  adj: Map<number, number[]>,
  start: number,
  target: number,
): number {
  const visited = new Set<number>([start]); // mark on enqueue
  let frontier = [start];
  let dist = 0;
  while (frontier.length > 0) {
    const next: number[] = [];
    for (const node of frontier) {
      if (node === target) return dist;
      for (const nb of adj.get(node) ?? []) {
        if (!visited.has(nb)) {
          visited.add(nb); // enqueue-time marking
          next.push(nb);
        }
      }
    }
    frontier = next; // advance one ring outward
    dist++;
  }
  return -1;
}

Big-O Complexity

Best
O(1)
Average
O(V + E)
Worst
O(V + E)
Space
O(V)

Every vertex is enqueued once and every edge examined once (twice for undirected graphs). Space is the queue plus the visited set — the queue can hold an entire frontier, up to O(V) on wide graphs.

In production When to use

Shortest unweighted path

When every edge costs the same, BFS finds the minimum-hop path by construction — routing hops in a network, fewest moves in a puzzle, minimum edits in a word ladder. No Dijkstra needed.

Degrees of separation

Social graphs answer how far apart are these two people? with BFS — friend suggestions, LinkedIn's 2nd/3rd-degree labels, and six-degrees analyses are all frontier-by-frontier expansions.

Web crawlers

Crawlers seed a queue with start URLs and expand outward level by level, which naturally prioritizes pages closer to the seeds and keeps a visited set to avoid re-fetching.

Garbage collection marking

Tracing collectors mark live objects by traversing references from the roots; Cheney's copying-collector algorithm is literally a BFS whose queue is the to-space being filled.

Level-order tree traversal

Printing a tree level by level, computing per-depth aggregates, or finding the minimum depth are BFS on a tree — the queue boundary is the level boundary.

Flood fill & connectivity

Paint-bucket fill, counting islands in a grid, and connected-component labeling treat grid cells as vertices with 4- or 8-neighbor edges and BFS from each unvisited seed.

Trade-offs Strengths & weaknesses

  • Guarantees the shortest path in edge count — the first arrival at a node is optimal.
  • Visits nodes in order of distance, so it can stop early at a target depth.
  • Iterative by nature: no recursion, no stack-overflow risk on huge graphs.
  • O(V + E) is optimal — every search that may need the whole graph must touch it once.
  • Distances and parent pointers fall out for free, reconstructing the actual path.
  • O(V) queue memory — on wide, bushy graphs the frontier can dwarf DFS's path-depth stack.
  • Shortest-path guarantee holds only for unweighted (or uniform-weight) graphs.
  • Needs the visited set from the very first step, or cycles loop it forever.
  • Poor fit for deep, narrow searches where the target is far from the start — it exhaustively fills every closer ring first.
  • Cache-unfriendly on pointer-based graphs: frontier nodes are scattered across memory.

Intuition Mental model

Ripples in a pond

Drop a stone in still water: rings spread outward, each ring one step farther than the last, and no point is wetted by a later ring before an earlier one reaches it. BFS is that wavefront — the queue holds the current ring, and distance is just which ring got there first.

  1. The stone hits the water = start node enqueued at distance 0.
  2. The first ring = all direct neighbors, discovered together at distance 1.
  3. Each ring expands only from the previous ring's edge = dequeue a node, enqueue its unseen neighbors at distance +1.
  4. Water already disturbed doesn't ripple again = the visited set, marked when the wave first touches it.
  5. The ring number when the wave hits your target = the shortest hop count, guaranteed, because no later ring can arrive earlier.

Prep Interview questions

Why does BFS find the shortest path in an unweighted graph? Prove it.
Induction on distance: BFS dequeues all nodes at distance d before any node at distance d+1 (the queue's distances are always monotone, spanning at most two consecutive values). So the first time a node is reached, it was reached from a distance-d node, giving distance d+1 — no shorter route can exist or it would have been found in an earlier ring.
Word Ladder: transform 'hit' to 'cog' one letter at a time through a dictionary. Why BFS?
Each word is a vertex, each one-letter change is an edge, every edge costs 1 — minimum transformations is a shortest unweighted path. Generate neighbors via 26 substitutions per position, and mark words visited as you enqueue them.
Rotting oranges / multi-source BFS: minutes until all oranges rot. What changes?
Seed the queue with ALL rotten oranges at time 0 instead of one source. Multi-source BFS is ordinary BFS from a virtual super-source; the answer is the depth of the last frontier.
When do you need Dijkstra or 0-1 BFS instead of plain BFS?
The moment edges carry unequal weights, BFS's first-arrival-is-optimal argument collapses. Weights of only 0 and 1 admit 0-1 BFS with a deque (0-edges pushed front, 1-edges pushed back); general non-negative weights need Dijkstra's priority queue.
BFS vs DFS: how do you choose in an interview?
BFS when the answer involves shortest, fewest steps, nearest, or level-by-level structure. DFS when it involves exhaustive exploration, backtracking, topological order, or cycle structure — and when memory favors path depth over frontier width.

Watch out Common bugs

Marking visited at dequeue instead of enqueue

If a node is only marked when popped, it can be pushed multiple times by different neighbors before its first pop — the queue balloons (up to O(E) entries) and work is duplicated. Mark visited at the moment of enqueue, so each vertex enters the queue exactly once.

No visited set at all

On any graph with a cycle (or just an undirected edge, which is a 2-cycle), the traversal revisits nodes forever. Trees are the only structure that forgives this — and interviewers know it.

Expecting shortest paths on weighted graphs

BFS counts hops, not weight. A 2-hop path of cost 100 will be found before a 3-hop path of cost 3. Weighted shortest paths need Dijkstra (or 0-1 BFS / Bellman-Ford as appropriate).

Using a stack (or list.pop()) where a queue belongs

Popping from the wrong end silently turns BFS into DFS — traversal still terminates, so the bug surfaces only as wrong distances. In Python, use collections.deque.popleft(), never list.pop(0), which is O(n) per dequeue.

One screen Cheat sheet

Queue + visited set: explore in rings, mark on enqueue, first arrival = shortest unweighted path.

Time O(V + E) · Space O(V)
  • Queue (FIFO) drives the level-by-level order — swap in a stack and you have DFS.
  • Mark visited when you ENQUEUE, not when you dequeue.
  • First arrival at a node is the shortest path in edge count — unweighted graphs only.
  • Track parent pointers to reconstruct the path, or a depth counter per frontier.
  • Multi-source BFS: seed the queue with several starts at distance 0.
  • Iterative and stack-safe, but the frontier can hold O(V) nodes on wide graphs.
Pick whenYou need shortest/fewest-hops answers, level-order structure, or nearest-first exploration on an unweighted graph.
Avoid whenEdges are weighted (use Dijkstra), the graph is deep and narrow with tight memory (consider DFS/IDDFS), or you need topological/cycle structure (DFS).

Trie Search

Depth-First Search (DFS)