文章目录
前言
本博客是对图的遍历做相关练习时所做笔记,主要内容来源队列与栈。
广度优先遍历建立在队列基础之上,深度优先遍历建立在栈基础之上,因此建议首先看一下队列与栈相关内容。
队列和广度优先遍历
广度优先遍历(BFS)
-
广度优先遍历是一种遍历或搜索的算法。特点访问完当前结点后,再去访问当前结点的所有邻接结点,层层推进。
可用队列实现BFS:首先将根结点加入队列。然后在每一轮中,逐个处理队列中的结点,并将结点的邻居加入队列。结点的处理顺序与它们添加到队列的顺序完全相同。
上图中,若以A为顶点,首先遍历A,然后遍历A的邻接结点B、C、D、F,按照队列先进先出的原则,再遍历B的邻接结点G,C的邻接结点E以及F的邻接结点H,所以遍历的顺序为ABCDFGEH。
-
广度优先遍历可用于在树中执行层序遍历,也可用来遍历图或找到图中从起始结点到目标结点的最短路径。
BFS中,越是接近根结点的结点将越早地被遍历,故可用来求根结点到目标结点的最短路径。
BFS模板
-
模板一:求最短路径
/** * 返回根结点到目标结点的最短路径 */ int BFS(Node root, Node target) { Queue<Node> queue; Set<Node> used; // 存储已访问过的结点 int step = 0; // 记录最短路径 // 初始化 add root to queue; //注意要第一时间标记已访问过,不要等到从队列弹出时再标记,那样会有很多重复 add root to used; // BFS while (!queue.isEmpty()) { // 距离根结点为step的结点个数 int size = queue.size(); for (int i = 0; i < size; ++i) { Node cur = queue.poll();//出队 return step if cur is target; //将当前结点未被访问过的相邻结点加入队列 for (Node next : the neighbors of cur) { if (next is not in used) { add next to queue; //注意要第一时间标记已访问过,不要等到从队列弹出时再标记,那样会有很多重复 add next to used; } } } step = step + 1; } return -1; // there is no path from root to target }
-
模板二:遍历图
/** * 遍历图中从根结点能到达的所有结点 */ void BFS(Node root) { Queue<Node> queue; Set<Node> used; // 存储已访问过的结点 // 初始化 add root to queue; add root to used; // BFS while (!queue.isEmpty()) { Node cur = queue.poll();//出队 System.out.println(cur); //将当前结点未被访问过的相邻结点加入队列 for (Node next : the neighbors of cur) { if (next is not in used) { add next to queue; add next to used; } } } }
286.墙与门
-
题目描述:你被给定一个 m × n 的二维网格,网格中有以下三种可能的初始化值:
-1 表示墙或是障碍物
0 表示一扇门
INF 无限表示一个空的房间。然后,我们用 2^31 - 1 = 2147483647 代表 INF。你可以认为通往门的距离总是小于 2147483647 的。
你要给每个空房间位上填上该房间到 最近 门的距离,如果无法到达门,则填 INF 即可。 -
示例:
给定二维网络: INF -1 0 INF INF INF INF -1 INF -1 INF -1 0 -1 INF INF 运行完你的函数后,该网格应该变成: 3 -1 0 1 2 2 1 -1 1 -1 2 -1 0 -1 3 4
-
**分析:**该题目其实就是让求所有结点到达门的最短距离。为-1可直接认为该结点不存在,即不可达。
因此,使用BFS可以很容易求出解:首先将所有为门的结点加入队列,其值为0,刚好可认为到达门的距离为0,然后从这些结点开始进行BFS,新结点的值为上一层结点的值加上1,更新值即可。当然,也不用再单独的用一个数组或集合去判断结点是否已经遍历,因为只要判断结点的值是否为INF即可确定还未遍历。其中,每个结点可用其在数组中的坐标表示,因此用一个长度为2的数组表示出其行列值即可。
-
代码:
class Solution { private static final int empty = Integer.MAX_VALUE; private static final int[][] neighbor = { { 0,1},{ 0,-1},{ 1,0},{ -1,0}}; public void wallsAndGates(int[][] rooms) { int row = rooms.length; if(row == 0) return; int col = rooms[0].length; Queue<int[]> queue = new LinkedList<>(); for(int i=0; i<row; i++) { for(int j=0; j<col; j++) { //当前结点为门就加入队列 if(rooms[i][j] == 0) { queue.offer(new int[]{ i,j}); } } } bfs(rooms, queue, row, col); } //rooms[i][j]为根结点,进行广度优先遍历来计算每个结点到根结点的最短距离 public void bfs(int[][] rooms, Queue<int[]> queue, int row, int col) { //BFS while(!queue.isEmpty()) { //队首元素出队 int[] cur = queue.poll(); //寻找cur相邻的结点,即上下左右四个结点能到达的结点,并加入队列 int x = cur[0]; int y = cur[1]; for(int i=0; i<neighbor.length; i++) { int r =<