BFS(广度优先搜索)

Breadth-First Search,广度优先搜索,是图遍历的两种基本方式之一。

核心思想

从起点开始,先访问所有距离为 1 的节点,再访问距离为 2 的节点,以此类推。就像水波一样一层层扩散。

类比:湖面投石,涟漪一圈圈向外扩散。

代码框架

// 图的 BFS 遍历框架
void traverse(Graph graph, int s, boolean[] visited) {
    Queue<Integer> q = new LinkedList<>();
    q.offer(s);
    visited[s] = true;

    while (!q.isEmpty()) {
        int cur = q.poll();
        System.out.println("visit " + cur);
        for (Edge e : graph.neighbors(cur)) {
            if (!visited[e.to]) {
                visited[e.to] = true;
                q.offer(e.to);
            }
        }
    }
}

关键特性

特性 说明
数据结构 队列(Queue)
遍历顺序 广度优先,一层层扩散
visited 数组 入队时标记(而非出队时),防止重复入队
适用场景 最短路径(无权图)、层级遍历、社交网络好友推荐

BFS 与最短路径

BFS 能保证首次到达某个节点时,走过的路径是最短的(仅适用于无权图权值相同的图)。

原因:BFS 按距离层级扩散,第一次碰到目标节点时,经过的边数最少。

BFS 算法框架

BFS 算法有三种常见写法:

  1. 简单写法:适用于简单图遍历,局限性大
  2. 常用写法(最常用):记录步数,适合求解最短路径问题
  3. 灵活写法:适用于复杂状态管理的问题

常用框架(带步数记录)

int bfs(int s, int target) {
    boolean[] visited = new boolean[graph.size()];
    Queue<Integer> q = new LinkedList<>();
    q.offer(s);
    visited[s] = true;
    int step = 0;
    while (!q.isEmpty()) {
        int sz = q.size();
        for (int i = 0; i < sz; i++) {
            int cur = q.poll();
            if (cur == target) return step;
            for (int to : neighborsOf(cur)) {
                if (!visited[to]) {
                    q.offer(to);
                    visited[to] = true;
                }
            }
        }
        step++;
    }
    return -1;
}

双向 BFS 优化

核心思想:从起点和终点同时开始扩散,当两边有交集时停止。

优势:比传统单向 BFS 更快,因为搜索空间增长速度是指数级的,双向搜索可以更快相遇。

局限性

  • 必须知道终点位置才能使用
  • 如二叉树最小深度问题,终点(最近的叶子节点)位置未知,无法使用

实现要点

  1. 使用哈希集合(而非队列),方便快速判断交集
  2. 每次选择元素数量少的集合进行扩散,减少搜索空间
  3. 在计算出邻居节点时就判断是否到达终点

参见:BFS框架(双向 BFS 完整代码示例)

与树层序遍历的关系

图的 BFS 本质上是N叉树遍历基础的延伸:

  • 树层序遍历不需要 visited 数组(树无环)
  • 图层序遍历必须加 visited 数组(图可能有环,防止重复入队)

二叉树层序遍历与 BFS 的关系

BFS 算法属于遍历思路,关注层级扩散:

  • 层序遍历 = BFS 在二叉树上的应用
  • 使用队列实现,一层层遍历节点
  • BFS 适合求无权图的最短路径

参见:二叉树系列算法核心纲领层序遍历

时间复杂度

$O(E + V)$,其中:

  • $E$ = 边的总数
  • $V$ = 节点的总数

BFS 与最短路径算法

BFS 是保证首次到达某个节点时路径最短(仅适用于无权图权值相同的图)。

基于此拓展的经典算法:

  • Dijkstra 算法:BFS + 贪心思想,处理带权重图的最短路径(不能处理负权重)
  • A* 算法:BFS + 启发式函数,点对点最短路径的优化(不能处理负权重)

来源

相关概念


Interactive Graph