深度优先和广度优先是在图和树的遍历搜索中比较常用的搜索方法
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/d04370ba28fe1d3ff0124c5b51b19022.png#pic_center#pic_center)
图的基本知识
日常有很多地方都用到了图,比如地铁线路图,计算机网络连线图等。
图就就是下面这种由节点和连接每对节点的边所构成的图形。
这是最简单的图,我们可以根据图的一些特性将其进行分类:
- 如果给边加上一个值表示权重,这种图就是加权图,没有权重的图就是非加权图,没有权重的边只能表示两个节点的连接状态,而有权重的边就可以表示节点之间的“连接程度”。
- 如果给边加上表示方向的箭头,即表示节点之间的传递方向,这种图就是有向图,而边上没有箭头的图就是无向图。
- 如果图中任意两个节点都能找到路径可以将它们进行连接,则称该图为连通图,上面这个图就是连通图,反之则为非连通图。
下面两个图分别为加权图和有向图:
非连通图如下所示:
知道了什么是图,和图相关的算法主要有两类:
图的搜索算法
:图的搜索指的就是从图的某一节点开始,通过边到达不同的节点,最终找到目标节点的过程。根据搜索的顺序不同,图的搜索算法可分为“广度优先搜索”和“深度优先搜索”两种。图的最短路径问题
:最短路径问题就是要在两个节点的所有路径中,找到一条所经过的边的权重总和最小的路径。相关算法有“贝尔曼-福特算法”,“狄克斯特拉算法”和“A*算法”三种。
深度优先
算法简介
DFS
是可用于遍历树或者图的搜索算法,DFS与回溯法
类似,一条路径走到底后需要返回上一步,搜索第二条路径。在树的遍历中,首先一直访问到最深的节点,然后回溯到它的父节点,遍历另一条路径,直到遍历完所有节点。图也类似,如果某个节点的邻居节点都已遍历,回溯到上一个节点。
深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题
等等。一般用栈
数据结构来辅助实现DFS算法。根据深度优先搜索的特点,采用递归函数实现比较简单
。但也可以不采用递归。
图解
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
算法实现
对于矩阵图的深度优先遍历
int dxy[4][2]={//模拟上下左右四个方向
-1,0,//向上(x减一,y不变)
1, 0,//向下
0,-1,//向左
0, 1//向右
}
void dfs(int x0,int y0)
{
if(x0,y0满足某种条件)//找到目标点
{
//执行操作如输出路径等
return;
}
for(int i=0;i<4;i++)//遍历四个方向每一个分支,对每一个分支都进行深度搜索
{
int dx=dxy[i][0];//移动后的横坐标
int dy=dxy[i][1];//移动后的纵坐标
if(坐标越界||遇到障碍物||...)//不满足条件
continue;
//执行操作
dfs(dx,dy)//深度遍历
//遍历结束恢复操作
}
}
广度优先
算法简介
广度搜索,顾名思义,就是更大范围内搜索,先访问完当前顶点的所有邻接点,然后再访问下一层的所有节点,该算法适用于解决最短、最小路径
等问题,但是构建广度优先算法需要维护自己的队列
。
广度搜索是同时搜索所有路径,相当于一层一层地搜索,就好比波浪的扩展一样。此搜索方法跟树的层次遍历
类似,因此宽度搜索一般都用队列存储结构
。
比如二叉树的层次遍历,我们大概会有如下几个步骤:
- 向Queue中放入root节点。
- 只要这个Queue中有元素就一直遍历。
- 每次遍历时,首先计算一下当前Queue里有多少个元素,这就是这棵树当前层级元素的数量,记作Size。
- 接下来从Queue中移除Size中的多个元素,对他们进行符合我们题目的一些操作。
- 移除每个节点时,把它们的子节点添加进Queue中。
- 只要Queue中还有元素,说明还有下一个层级,就一直重复步骤3去处理下一个层级。
图解
![]() |
![]() |
![]() |
![]() |
![]() |
static const int dirs[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
void bfs(int row, int col) {
if (row,col满足某种条件) {
return;
}
int * queue = (int *)malloc(sizeof(int) * m * n);
int head = 0;
int tail = 0; 双指针实现队列先进先出
queue[tail++] = row * n + col;
while (head != tail) {
int row = queue[head] / n;
int col = queue[head] % n;
head++;
for (int i = 0; i < 4; i++) {
int newRow = row + dirs[i][0], newCol = col + dirs[i][1];
if 满足某种条件(newRow >= 0 && newRow < m && newCol >= 0 && newCol < n &&……) {
对点进行某种操作操作
queue[tail++] = newRow * n + newCol;
}
}
}
free(queue);
}