Menu
Coddy logo textTech

Breadth-First Search (BFS)

Last updated

Breadth-first search explores a graph level by level. Starting from a source node, it visits all of its immediate neighbors first, then all of their unvisited neighbors, and so on - expanding outward in rings of increasing distance. Press play above to watch it fan out from the start node one layer at a time.

BFS uses a first-in-first-out queue, which is what enforces the level-by-level order. Because it reaches nodes in order of hop distance, BFS finds the shortest path (fewest edges) in an unweighted graph. It visits every node and edge once, so it runs in O(V + E) time.

Time & space complexity

MeasureComplexityNotes
TimeO(V + E)Every vertex and edge visited once
SpaceO(V)Queue + visited set, worst case all nodes
TraversalLevel by levelNearest nodes first, in rings
Shortest pathYes (unweighted)Reaches each node by fewest edges

Step by step

StepWhat happens
1Enqueue the source node.
2Dequeue the front node and mark it visited.
3Look at each of its neighbors.
4Enqueue any neighbor not already visited or queued.
5Repeat until the queue is empty.

Worked example

Traversing this graph from node 0, where 0-1, 0-2, 1-3, 2-3, 2-4 are edges:

StepVisitedQueue (frontier)
Start{}[0]
Dequeue 0{0}[1, 2]
Dequeue 1{0, 1}[2, 3]
Dequeue 2{0, 1, 2}[3, 4]
Dequeue 3{0, 1, 2, 3}[4]
Dequeue 4{0, 1, 2, 3, 4}[] (done)

When to use BFS

Use it whenAvoid it when
You need the shortest path in an unweighted graphEdges have weights - use Dijkstra instead
The target is likely close to the sourceThe graph is very wide - the queue can hold a huge frontier
You want to explore a graph in level orderYou only need to reach any node, where DFS uses less memory
You are finding connected components or a minimum-hop routeYou need topological sorting or cycle detection - DFS fits better

Breadth-First Search code

A clean, runnable Breadth-First Search implementation in Python, JavaScript, Java, C++, C. Pick a language, copy the code, or open it pre-loaded in the Coddy Playground.

Breadth-First Search code in Python

Python
1from collections import deque2
3
4def bfs(graph, start):5    visited = {start}6    queue = deque([start])7    order = []8    while queue:9        node = queue.popleft()10        order.append(node)11        for neighbor in graph[node]:12            if neighbor not in visited:13                visited.add(neighbor)  # mark on enqueue, not dequeue14                queue.append(neighbor)15    return order16
17
18graph = {19    "A": ["B", "C"],20    "B": ["D", "E"],21    "C": ["F"],22    "D": [],23    "E": ["F"],24    "F": [],25}26
27print("BFS order:", " -> ".join(bfs(graph, "A")))
Run this code in the Python Playground

Breadth-First Search FAQ

What is the time complexity of BFS?
BFS runs in O(V + E) time, where V is the number of vertices and E the number of edges, since it visits each vertex once and examines each edge once. It uses O(V) space for the queue and visited set.
Does BFS find the shortest path?
Yes, in an unweighted graph. Because BFS reaches nodes in order of hop distance from the source, the first time it reaches a node is along a path with the fewest edges. For weighted graphs you need Dijkstra's algorithm instead.
What is the difference between BFS and DFS?
BFS uses a queue and explores level by level (nearest first), while DFS uses a stack and dives deep along one branch before backtracking. BFS finds shortest unweighted paths; DFS uses less memory on wide graphs and suits cycle detection and topological sorting.
When should I use BFS instead of Dijkstra's algorithm?
Use BFS when every edge has the same cost, because it finds the fewest-edge path in O(V + E) time without a priority queue. Dijkstra's algorithm is needed when edges carry different weights; running plain BFS on a weighted graph gives the shortest-hop path, not the lowest-cost one.
Why does BFS need a visited set?
Graphs can contain cycles, so without a visited set BFS would enqueue the same node repeatedly and loop forever. Marking a node when you first enqueue it (not when you dequeue it) also prevents the same node from being added to the queue twice by different neighbors.
Should I mark a node visited when enqueuing or dequeuing it?
Mark it when you enqueue it. If you wait until you dequeue it, a node can be added to the queue multiple times by different neighbors before it is processed, wasting memory and time. Marking on enqueue guarantees each node enters the queue exactly once.
Coddy programming languages illustration

Master algorithms with Coddy

GET STARTED