广度优先搜索算法:先查找离起始顶点最近的,然后是第二进的,这样依次往外搜索。树的层次遍历就是一个广度搜索算法。
一般需要用到队列这个数据结构,但是如果你是C语言开发,并且是在考试中,时间有限。一般临时写一个队列出来还是很耗时间的,所以一般用一个大数组来模拟队列。
根据百度百科:广度优先搜索算法在求解最短路径或者最短步数上有很多的应用。应用最多的是在走迷宫上。
今天做了两道力扣题目,总结一下BFS的套路:
第一题: 542. 01 矩阵
C代码实现:

1 /* 广度优先: 用大数组实现队列 */ 2 #define MAX_SIZE 10000 3 int numSquares(int n) 4 { 5 int queue[MAX_SIZE] = {0}; 6 int front = 0; // 队首 7 int rear = 0; // 队尾 8 int size = 0; // 当前队列中元素的个数 9 int visit[MAX_SIZE] = {0}; // visit[i]表示元素i是否已经访问过 10 11 // 初始化队列 12 queue[0] = n; 13 rear++; 14 visit[n] = 1; 15 int result = 0; 16 while (front < rear) { // 循环终止的条件是队列为空 17 size = rear - front; 18 result++; // 每循环一轮,说明遍历了一层,离答案就近了一层 19 for (int i = 0; i < size; i++) { 20 int topElem = queue[front]; // 队首元素出队列 21 front++; 22 for (int j = 1; j * j <= topElem; j++) { 23 int nextElem = topElem - j * j; 24 if (nextElem == 0) { 25 return result; 26 } 27 // 入队列 28 if (visit[nextElem] != 1) { 29 visit[nextElem] = 1; 30 queue[rear++] = nextElem; 31 } 32 } 33 } 34 } 35 return result; 36 }
第二题:490. 迷宫
C代码实现:

1 typedef struct tagPos { 2 int rowIndex; 3 int colIndex; 4 } Pos; 5 6 bool hasPath(int** maze, int mazeSize, int* mazeColSize, int* start, int startSize, int* destination, int destinationSize){ 7 int rowSize = mazeSize; 8 int colSize = mazeColSize[0]; 9 int visit[rowSize][colSize]; 10 for (int i = 0; i < rowSize; i++) { 11 for (int j = 0; j < colSize; j++) { 12 visit[i][j] = 0; 13 } 14 } 15 int max_size = rowSize * colSize; 16 Pos queue[max_size]; 17 int front = 0; 18 int rear = 0; 19 // int size; 20 queue[0].rowIndex = start[0]; 21 queue[0].colIndex = start[1]; 22 rear++; 23 visit[start[0]][start[1]] = 1; 24 int direct[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; 25 while (front < rear) { 26 Pos curr = queue[front]; 27 front++; 28 if (curr.rowIndex == destination[0] && curr.colIndex == destination[1]) { 29 return true; 30 } 31 for (int i = 0; i < 4; i++) { 32 int x = curr.rowIndex + direct[i][0]; 33 int y = curr.colIndex + direct[i][1]; 34 while (x >= 0 && x < rowSize && y >= 0 && y < colSize && maze[x][y] == 0) { 35 printf("go on, x:%d, y%d ", x, y); 36 x += direct[i][0]; 37 y += direct[i][1]; 38 } 39 /* 走到这里x, y如果是有效的。那么maze[x][y]一定为 1 40 * 所以需要按照原来的方向退一格。所以是: 41 * x -= direct[i][0] y -= direct[i][1]; 42 * 然后再判断移位之后x,y 的情况 43 */ 44 x -= direct[i][0]; 45 y -= direct[i][1]; 46 if (x >= 0 && x < rowSize && y >= 0 && y < colSize && visit[x][y] != 1) { 47 queue[rear].rowIndex = x; 48 queue[rear].colIndex = y; 49 printf("keep: x:%d, y:%d ", x, y); 50 rear++; 51 visit[x][y] = 1; 52 } 53 } 54 } 55 return false; 56 }
总结:
经过上面两道题,看到别人总结了BFS的套路,现摘抄如下:
BFS 使用队列,把每个还没有搜索到的点依次放入队列,然后再弹出队列的头部元素当做当前遍历点。BFS 总共有两个模板:
1、如果不需要确定当前遍历到了哪一层,BFS 模板如下。

1 while queue 不空: 2 cur = queue.pop() 3 for 节点 in cur的所有相邻节点: 4 if 该节点有效且未访问过: 5 queue.push(该节点)
2、
如果要确定当前遍历到了哪一层,BFS 模板如下。
这里增加了 level 表示当前遍历到二叉树中的哪一层了,也可以理解为在一个图中,现在已经走了多少步了。size 表示在当前遍历层有多少个元素,也就是队列中的元素数,我们把这些元素一次性遍历完,即把当前层的所有元素都向外走了一步。

1 level = 0 2 while queue 不空: 3 size = queue.size() 4 while (size --) { 5 cur = queue.pop() 6 for 节点 in cur的所有相邻节点: 7 if 该节点有效且未被访问过: 8 queue.push(该节点) 9 } 10 level ++;
参考资料:
(1) : https://leetcode-cn.com/problems/01-matrix/solution/tao-lu-da-jie-mi-gao-dong-ti-mu-kao-cha-shi-yao-2/