Back to Home

Graph BFS (Breadth-First Search)

BFS explores a graph level by level, visiting all neighbors before moving to the next level. It's ideal for finding shortest paths in unweighted graphs and level-order traversals.

When to Use

  • Shortest path in unweighted graphs
  • Level-order traversal of trees
  • Finding connected components
  • Problems requiring 'minimum steps' or 'minimum moves'

Common Patterns

Standard BFS

Use queue to process nodes level by level

Example: Binary tree level order, shortest path in grid

Multi-source BFS

Start BFS from multiple sources simultaneously

Example: Rotting oranges, walls and gates

Code Templates

Python

from collections import deque

def bfs(graph, start):
    visited = set([start])
    queue = deque([start])
    
    while queue:
        node = queue.popleft()
        
        # Process node
        process(node)
        
        # Visit neighbors
        for neighbor in graph[node]:
            if neighbor not in visited:
                visited.add(neighbor)
                queue.append(neighbor)
    
    return visited

# Grid BFS template
def bfs_grid(grid, start_row, start_col):
    rows, cols = len(grid), len(grid[0])
    visited = set([(start_row, start_col)])
    queue = deque([(start_row, start_col, 0)])  # row, col, distance
    directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
    
    while queue:
        row, col, dist = queue.popleft()
        
        # Process cell
        if is_target(grid[row][col]):
            return dist
        
        # Explore neighbors
        for dr, dc in directions:
            new_row, new_col = row + dr, col + dc
            
            if (0 <= new_row < rows and 
                0 <= new_col < cols and 
                (new_row, new_col) not in visited and
                grid[new_row][new_col] != obstacle):
                
                visited.add((new_row, new_col))
                queue.append((new_row, new_col, dist + 1))
    
    return -1

C++

#include <vector>
#include <queue>
#include <unordered_set>
using namespace std;

void bfs(vector<vector<int>>& graph, int start) {
    unordered_set<int> visited;
    queue<int> q;
    
    visited.insert(start);
    q.push(start);
    
    while (!q.empty()) {
        int node = q.front();
        q.pop();
        
        // Process node
        process(node);
        
        // Visit neighbors
        for (int neighbor : graph[node]) {
            if (visited.find(neighbor) == visited.end()) {
                visited.insert(neighbor);
                q.push(neighbor);
            }
        }
    }
}

// Grid BFS template
int bfsGrid(vector<vector<int>>& grid, int startRow, int startCol) {
    int rows = grid.size(), cols = grid[0].size();
    vector<vector<bool>> visited(rows, vector<bool>(cols, false));
    queue<tuple<int, int, int>> q;  // row, col, distance
    
    visited[startRow][startCol] = true;
    q.push({startRow, startCol, 0});
    
    int directions[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    
    while (!q.empty()) {
        auto [row, col, dist] = q.front();
        q.pop();
        
        // Process cell
        if (isTarget(grid[row][col])) {
            return dist;
        }
        
        // Explore neighbors
        for (auto& dir : directions) {
            int newRow = row + dir[0];
            int newCol = col + dir[1];
            
            if (newRow >= 0 && newRow < rows && 
                newCol >= 0 && newCol < cols &&
                !visited[newRow][newCol] &&
                grid[newRow][newCol] != OBSTACLE) {
                
                visited[newRow][newCol] = true;
                q.push({newRow, newCol, dist + 1});
            }
        }
    }
    
    return -1;
}

Practice Problems

Common Pitfalls

  • ⚠️Forgetting to mark nodes as visited before adding to queue (can lead to duplicates)
  • ⚠️Not tracking distance/level when needed
  • ⚠️Using list instead of deque for queue (inefficient)
  • ⚠️Incorrect boundary checks in grid problems

Complexity

Time
O(V + E) where V = vertices, E = edges
Space
O(V) for queue and visited set

More space than DFS but guarantees shortest path

Prerequisites