news 2026/5/30 9:54:04

BFS(广度优先搜索)及经典变种 + Java 实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
BFS(广度优先搜索)及经典变种 + Java 实现

目录

一、BFS(广度优先搜索)及经典变种 + Java 实现

1. 基础 BFS 原理

1.1 基础 BFS(邻接表实现 无向图)

1.2 BFS 变种 1:带路径记录的 BFS(无权最短路径)

1.3 BFS 变种 2:多源 BFS

1.4 BFS 变种 3:双向 BFS


一、BFS(广度优先搜索)及经典变种 + Java 实现

1. 基础 BFS 原理

核心思想:按遍历图 / 树,使用队列实现,先访问当前节点所有邻接节点,再遍历下一层。

  • 适用:无权图最短路径、迷宫遍历、层次遍历、连通块统计
  • 特点:无权图中,首次到达目标节点的路径就是最短路径

1.1 基础 BFS(邻接表实现 无向图)

import java.util.*; public class BasicBFS { // 邻接表存图 private static List<List<Integer>> graph; // 标记是否访问 private static boolean[] visited; public static void main(String[] args) { int n = 6; // 节点数 0~5 initGraph(n); // 从节点 0 开始 BFS bfs(0); } // 初始化图 private static void initGraph(int n) { graph = new ArrayList<>(); for (int i = 0; i < n; i++) { graph.add(new ArrayList<>()); } // 构建边 graph.get(0).add(1); graph.get(0).add(2); graph.get(1).add(0); graph.get(1).add(3); graph.get(2).add(0); graph.get(2).add(4); graph.get(3).add(1); graph.get(3).add(5); graph.get(4).add(2); graph.get(5).add(3); visited = new boolean[n]; } // 基础 BFS public static void bfs(int start) { Queue<Integer> queue = new LinkedList<>(); queue.offer(start); visited[start] = true; while (!queue.isEmpty()) { int cur = queue.poll(); System.out.print(cur + " "); // 遍历所有邻接节点 for (int next : graph.get(cur)) { if (!visited[next]) { visited[next] = true; queue.offer(next); } } } } }

输出:0 1 2 3 4 5


1.2 BFS 变种 1:带路径记录的 BFS(无权最短路径)

在基础 BFS 上增加前驱数组,回溯得到完整路径。

import java.util.*; public class BFS_ShortestPath { private static List<List<Integer>> graph; private static int[] pre; // 前驱节点,记录路径 public static void main(String[] args) { int n = 6; initGraph(n); int start = 0; int end = 5; bfsPath(start, n); // 回溯输出路径 printPath(start, end); } private static void initGraph(int n) { graph = new ArrayList<>(); for (int i = 0; i < n; i++) graph.add(new ArrayList<>()); graph.get(0).add(1); graph.get(0).add(2); graph.get(1).add(0); graph.get(1).add(3); graph.get(2).add(0); graph.get(2).add(4); graph.get(3).add(1); graph.get(3).add(5); graph.get(4).add(2); graph.get(5).add(3); } public static void bfsPath(int start, int n) { boolean[] visited = new boolean[n]; pre = new int[n]; Arrays.fill(pre, -1); // -1 表示无前驱 Queue<Integer> q = new LinkedList<>(); q.offer(start); visited[start] = true; while (!q.isEmpty()) { int cur = q.poll(); for (int next : graph.get(cur)) { if (!visited[next]) { visited[next] = true; pre[next] = cur; q.offer(next); } } } } // 回溯打印路径 public static void printPath(int start, int end) { List<Integer> path = new ArrayList<>(); int cur = end; while (cur != -1) { path.add(cur); cur = pre[cur]; } Collections.reverse(path); System.out.println("最短路径:" + path); } }

输出:最短路径:[0, 1, 3, 5]


1.3 BFS 变种 2:多源 BFS

场景:多个起点同时向外层扩散(如:多起点迷宫、洪水填充、最近距离)。 原理:初始队列一次性加入所有源点,后续逻辑和普通 BFS 一致。

示例:求每个节点距离最近源点的距离

import java.util.*; public class MultiSourceBFS { public static void main(String[] args) { // 网格:0=空地,1=源点 int[][] grid = { {1, 0, 0}, {0, 0, 0}, {0, 0, 1} }; int[][] dist = multiSourceBFS(grid); // 打印距离矩阵 for (int[] row : dist) { System.out.println(Arrays.toString(row)); } } // 上下左右四个方向 private static final int[][] dirs = {{-1,0},{1,0},{0,-1},{0,1}}; public static int[][] multiSourceBFS(int[][] grid) { int m = grid.length, n = grid[0].length; int[][] dist = new int[m][n]; boolean[][] visited = new boolean[m][n]; Queue<int[]> queue = new LinkedList<>(); // 1. 多源:所有 1 作为起点入队 for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (grid[i][j] == 1) { queue.offer(new int[]{i, j}); visited[i][j] = true; dist[i][j] = 0; } } } // 2. 层序遍历 while (!queue.isEmpty()) { int[] cur = queue.poll(); int x = cur[0], y = cur[1]; for (int[] d : dirs) { int nx = x + d[0]; int ny = y + d[1]; if (nx >= 0 && nx < m && ny >=0 && ny < n && !visited[nx][ny]) { visited[nx][ny] = true; dist[nx][ny] = dist[x][y] + 1; queue.offer(new int[]{nx, ny}); } } } return dist; } }

1.4 BFS 变种 3:双向 BFS

场景:起点、终点已知,大幅减少搜索节点(单向 BFS 层数爆炸时优化)。 原理:起点队列、终点队列同时向中间遍历,两边相遇即找到最短路径。

import java.util.*; public class TwoWayBFS { private static List<List<Integer>> graph; public static void main(String[] args) { int n = 6; initGraph(n); int start = 0, end = 5; int res = twoWayBFS(start, end, n); System.out.println("最短路径长度:" + res); } private static void initGraph(int n) { graph = new ArrayList<>(); for (int i = 0; i < n; i++) graph.add(new ArrayList<>()); graph.get(0).add(1); graph.get(0).add(2); graph.get(1).add(0); graph.get(1).add(3); graph.get(2).add(0); graph.get(2).add(4); graph.get(3).add(1); graph.get(3).add(5); graph.get(4).add(2); graph.get(5).add(3); } public static int twoWayBFS(int start, int end, int n) { if (start == end) return 0; Queue<Integer> qStart = new LinkedList<>(); Queue<Integer> qEnd = new LinkedList<>(); Set<Integer> visStart = new HashSet<>(); Set<Integer> visEnd = new HashSet<>(); qStart.offer(start); qEnd.offer(end); visStart.add(start); visEnd.add(end); int step = 0; while (!qStart.isEmpty() && !qEnd.isEmpty()) { step++; // 正向遍历一层 int size = qStart.size(); for (int i = 0; i < size; i++) { int cur = qStart.poll(); for (int next : graph.get(cur)) { if (visEnd.contains(next)) return step; // 相遇 if (!visStart.contains(next)) { visStart.add(next); qStart.offer(next); } } } step++; // 反向遍历一层 size = qEnd.size(); for (int i = 0; i < size; i++) { int cur = qEnd.poll(); for (int next : graph.get(cur)) { if (visStart.contains(next)) return step; // 相遇 if (!visEnd.contains(next)) { visEnd.add(next); qEnd.offer(next); } } } } return -1; // 不可达 } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/30 9:46:56

毫米波雷达LD2410C人体存在检测:原理、应用与Arduino/ESP32实战

1. 项目概述&#xff1a;从“动静”到“存在”的感知革命在智能家居和安防领域&#xff0c;我们习惯了依赖摄像头、红外热释电&#xff08;PIR&#xff09;传感器来感知人的存在。但摄像头有隐私顾虑&#xff0c;PIR传感器对静止的人体束手无策&#xff0c;且易受温度、气流干扰…

作者头像 李华
网站建设 2026/5/30 9:46:33

如何快速批量下载Iwara高清视频:终极免费工具完整指南

如何快速批量下载Iwara高清视频&#xff1a;终极免费工具完整指南 【免费下载链接】IwaraDownloadTool Iwara 下载工具 | Iwara Downloader 项目地址: https://gitcode.com/gh_mirrors/iw/IwaraDownloadTool 你是否曾经在Iwara平台上看到精彩的视频&#xff0c;想要收藏…

作者头像 李华
网站建设 2026/5/30 9:41:21

AI风控实战:从规则驱动到智能感知的移动支付安全进化

1. 项目概述&#xff1a;当AI成为移动钱包的“守门人” 移动支付已经像空气一样无处不在&#xff0c;从街边买个煎饼到商场里的大额消费&#xff0c;掏出手机“滴”一声就完成了。但便利的背后&#xff0c;是欺诈者日益猖獗的“黑手”。传统的风控规则&#xff0c;比如“单笔交…

作者头像 李华
网站建设 2026/5/30 9:40:19

别再乱接线了!STM32F103C8T6驱动L298N控制编码电机的保姆级避坑指南

STM32F103C8T6与L298N驱动编码电机实战&#xff1a;从硬件避坑到精准控制 刚拿到STM32开发板和L298N电机驱动模块时&#xff0c;很多初学者都会迫不及待地开始接线&#xff0c;结果往往遇到电机不转、模块发烫、编码器读数异常等问题。这些问题90%都源于几个关键环节的疏忽——…

作者头像 李华