一、BFS是什么
广度优先搜索(Breadth-First Search,BFS)是一种用于遍历或搜索树或图的算法。它从起始节点开始,首先访问起始节点的所有邻接节点,然后再依次访问这些邻接节点的邻接节点,以此类推,一层一层地向外扩展,直到找到目标节点或者遍历完整个图或树。
BFS的核心思想可以概括为“全面扩散、逐层递进”。这一思想源于其处理方式:从起始节点开始,逐层扩展至更深的节点。在实现时,BFS通常使用队列(Queue)来实现,因为队列的先进先出(FIFO)特性保证了节点按照层次顺序被访问。
核心思想
广度优先搜索(Breadth-First Search,BFS)是一种用于遍历或搜索树或图的算法。它从起始节点开始,逐层向外扩展,直到找到目标节点或遍历完整个图。
实现方式
- 数据结构:队列(Queue)
- 时间复杂度:O(V+E)(V为顶点数,E为边数)
- 空间复杂度:O(V)
对比特点
特性 | BFS | DFS |
数据结构 | 队列 | 栈 |
空间复杂度 | O(宽) | O(深) |
适用场景 | 最短路径 | 拓扑排序等 |
二、BFS的特点
- 逐层遍历:BFS会按照节点的层次进行遍历,先访问离起始节点最近的所有节点,再依次访问距离更远的层次。
- 使用队列:在实现时,BFS利用队列来存储当前访问的节点,每次从队列头部取出一个节点进行处理,并将其未访问的邻接节点依次放入队列尾部。
- 适用于最短路径问题:在无权图中,BFS可以保证找到从起点到目标节点的最短路径,因为其逐层扩展的特性确保了最先到达目标节点的路径就是最短路径。
三、BFS的应用场景
- 寻找最短路径:BFS可以用来寻找从一个顶点到其他顶点的最短路径。例如,在迷宫问题中,找到从起点到终点的最短路径。
- 图的连通性判断:通过BFS可以判断一个图是否是连通图,即图中任意两个顶点之间是否都存在路径相连。
- 层序遍历:需要按层遍历树或图的节点时,BFS是首选算法。比如,在二叉树的层序遍历中,使用BFS可以方便地按层输出节点值。
四、BFS在蓝桥杯中的应用
例题一:迷宫寻路
题目描述
给定一个N×M的网格迷宫,其中每个格子要么是道路(用1表示),要么是障碍物(用0表示)。已知迷宫的入口位置为(x1,y1),出口位置为(x2,y2),问从入口走到出口,最少要走多少个格子。
输入
- 第1行包含两个正整数N和M,分别表示迷宫的大小。
- 接下来输入一个N×M的矩阵,若G[i][j]=1表示其为道路,否则表示其为障碍物。
- 最后一行输入四个整数x1,y1,x2,y2,表示入口的位置和出口的位置。
输出
输出从入口到出口的最少步数,如果无法到达,则输出-1。
分析
这是一个典型的最短路径问题,可以使用BFS来解决。BFS的逐层扩展特性保证了最先到达出口的路径就是最短路径。具体步骤如下:
- 初始化:创建一个队列,将入口位置作为起始节点入队,并标记为已访问。
- 队列处理:每次从队列中取出一个节点,检查是否为出口位置,如果是则返回当前步数。
- 扩展节点:对于当前节点的四个方向(上、下、左、右),检查是否可以移动(是否在迷宫范围内、是否为道路且未被访问过),如果可以则将该位置入队,并标记为已访问,同时记录步数。
- 循环结束:如果队列为空且未找到出口,则说明无法到达,返回-1。
解题思路
- 创建队列并将起始位置入队
- 初始化距离数组
- 沿四个方向扩展
- 找到出口时返回距离
Java代码实现
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class MazeBFS {
static int[][] maze;
static boolean[][] visited;
static int[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; // 四个方向
static int rows, cols;
static int startRow, startCol, endRow, endCol;
static int minSteps = -1;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
rows = scanner.nextInt();
cols = scanner.nextInt();
maze = new int[rows][cols];
visited = new boolean[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
maze[i][j] = scanner.nextInt();
}
}
startRow = scanner.nextInt() - 1; // 转换为从0开始的索引
startCol = scanner.nextInt() - 1;
endRow = scanner.nextInt() - 1;
endCol = scanner.nextInt() - 1;
bfs();
System.out.println(minSteps);
}
public static void bfs() {
Queue<int[]> queue = new LinkedList<>();
queue.offer(new int[]{startRow, startCol, 0});
visited[startRow][startCol] = true;
while (!queue.isEmpty()) {
int[] current = queue.poll();
int currentRow = current[0];
int currentCol = current[1];
int steps = current[2];
if (currentRow == endRow && currentCol == endCol) {
minSteps = steps;
return;
}
for (int[] dir : dirs) {
int newRow = currentRow + dir[0];
int newCol = currentCol + dir[1];
if (newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols && maze[newRow][newCol] == 1 && !visited[newRow][newCol]) {
visited[newRow][newCol] = true;
queue.offer(new int[]{newRow, newCol, steps + 1});
}
}
}
}
}
解释:
假设输入的迷宫如下:
5 5
1 1 1 1 1
1 0 0 0 1
1 0 1 0 1
1 0 0 0 1
1 1 1 1 1
1 1 5 5
迷宫的布局如下图所示:
S表示入口,E表示出口,0表示障碍物,1表示道路。
S 1 1 1 1
1 0 0 0 1
1 0 1 0 1
1 0 0 0 1
1 1 1 1 E
BFS的搜索过程如下图所示:
首先将入口位置(1,1)入队,标记为已访问。
然后依次处理队列中的节点,按照四个方向扩展。
当搜索到出口位置(5,5)时,返回当前步数。
例题二:二叉树的最短路径
题目描述
给定一棵二叉树,找到从根节点到叶子节点的最短路径的深度。
输入
输入为二叉树的节点结构,可以通过递归或其他方式构建。
输出
输出最短路径的深度。
分析
二叉树的层序遍历可以使用BFS来实现,通过逐层遍历,找到第一个叶子节点时的深度即为最短路径的深度。具体步骤如下:
- 初始化:创建一个队列,将根节点入队,并初始化深度为1。
- 队列处理:每次从队列中取出一层的节点数量,逐个处理这些节点。
- 检查叶子节点:对于每个节点,如果其左右子节点都为空,则说明是叶子节点,返回当前深度。
- 扩展节点:将当前节点的非空子节点入队。
- 深度增加:每处理完一层,深度加1。
解题思路
- 将根节点入队
- 记录当前层数
- 遇到第一个叶子节点时返回结果
避坑指南
- 空树检查
- 子节点入队逻辑
- 层数统计
Java代码实现
import java.util.LinkedList;
import java.util.Queue;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public class MinDepthBFS {
public static int minDepth(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int depth = 1;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (node.left == null && node.right == null) {
return depth;
}
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
depth++;
}
return depth;
}
public static void main(String[] args) {
// 示例构建二叉树
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
System.out.println(minDepth(root)); // 输出2
}
}
解释:
假设输入的二叉树如下:
1
/ \
2 3
/ \
4 5
BFS的搜索过程如下图所示:
首先将根节点1入队,深度初始化为1。
处理根节点1,发现其不是叶子节点,将左右子节点2和3入队。
处理第二层的节点2和3,发现节点3是叶子节点,返回当前深度2。
五、总结
掌握BFS算法不仅有助于蓝桥杯等赛事,更是提升编程能力的关键。随着全球AI竞赛进入白热化阶段 ,算法能力变得更加重要。
📌 相关热门推荐:
- 《DFS算法深度解析》
- 《动态规划解题套路》
- 《蓝桥杯历年真题汇总》
🔗 本文代码已通过CSDN在线测试,如需获取完整可运行代码,请三连后在评论区留言!
📊 读者互动: 你觉得BFS在算法竞赛中最难的部分是? A) 队列实现 B) 边界处理 C) 最短路径证明