【数据结构与算法】广度优先搜索(BFS)
时间:2020-04-25
本文章向大家介绍【数据结构与算法】广度优先搜索(BFS),主要包括【数据结构与算法】广度优先搜索(BFS)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
广度优先搜索算法:先查找离起始顶点最近的,然后是第二进的,这样依次往外搜索。树的层次遍历就是一个广度搜索算法。
一般需要用到队列这个数据结构,但是如果你是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\n", 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/
原文地址:https://www.cnblogs.com/LydiammZuo/p/12774490.html
- radio与checkbox
- JavaScript之cookie
- Silverlight学习(四) domainservice动态多条件查询
- Android学习Tabhost、gallery、listview、imageswitcher
- ProgressBar、RatingBar和Spinner控件
- TimePicker控件、帧动画、补间动画
- Android学习之简单的数据存储
- Android学习之菜单
- Android简单登录系统
- android自定义控件
- 测试是浪费时间,我的程序肯定没问题
- Android学习自定义Dialog
- Android学习之DialogFragment
- Intent组件
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- centos内核的删除或修改
- chkconfig学习笔记
- 3分钟短文:说说Laravel通用缓存Cache的使用技巧
- 【技术创作101训练营】想用代码改变世界?先用好Git和Github!
- 绘制散点图(克利夫兰系列)
- 绘制分组散点图(克里夫兰点图)
- ggplot2绘制玫瑰图
- 绘制极坐标系条形图
- 四步重新认识冗余机器人的控制器设计
- 人脸识别接入常见问题汇总
- TKE上关于postStart 和preStop使用
- 文字识别接入常见问题
- 从 1 到 0 构建博客项目(2) -- 操作系统篇(2)--定制Centos
- 使用Angular依赖注入自定义SAP Spartacus的ProductAdapter
- 获取SAP Spartacus当前显示产品json数据的又一办法