图、深搜(DFS)和广搜(BFS) 数据结构篇-2


深度优先和广度优先是在图和树的遍历搜索中比较常用的搜索方法
在这里插入图片描述

图的基本知识

日常有很多地方都用到了图,比如地铁线路图,计算机网络连线图等。

图就就是下面这种由节点和连接每对节点的边所构成的图形。
在这里插入图片描述
这是最简单的图,我们可以根据图的一些特性将其进行分类:

  • 如果给边加上一个值表示权重,这种图就是加权图,没有权重的图就是非加权图,没有权重的边只能表示两个节点的连接状态,而有权重的边就可以表示节点之间的“连接程度”。
  • 如果给边加上表示方向的箭头,即表示节点之间的传递方向,这种图就是有向图,而边上没有箭头的图就是无向图。
  • 如果图中任意两个节点都能找到路径可以将它们进行连接,则称该图为连通图,上面这个图就是连通图,反之则为非连通图。

下面两个图分别为加权图和有向图:在这里插入图片描述
非连通图如下所示:
在这里插入图片描述
知道了什么是图,和图相关的算法主要有两类:

  • 图的搜索算法:图的搜索指的就是从图的某一节点开始,通过边到达不同的节点,最终找到目标节点的过程。根据搜索的顺序不同,图的搜索算法可分为“广度优先搜索”和“深度优先搜索”两种。
  • 图的最短路径问题:最短路径问题就是要在两个节点的所有路径中,找到一条所经过的边的权重总和最小的路径。相关算法有“贝尔曼-福特算法”,“狄克斯特拉算法”和“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)//深度遍历
		//遍历结束恢复操作
	}
}

广度优先

算法简介

广度搜索,顾名思义,就是更大范围内搜索,先访问完当前顶点的所有邻接点,然后再访问下一层的所有节点,该算法适用于解决最短、最小路径等问题,但是构建广度优先算法需要维护自己的队列
广度搜索是同时搜索所有路径,相当于一层一层地搜索,就好比波浪的扩展一样。此搜索方法跟树的层次遍历类似,因此宽度搜索一般都用队列存储结构

比如二叉树的层次遍历,我们大概会有如下几个步骤:

  1. 向Queue中放入root节点。
  2. 只要这个Queue中有元素就一直遍历。
  3. 每次遍历时,首先计算一下当前Queue里有多少个元素,这就是这棵树当前层级元素的数量,记作Size。
  4. 接下来从Queue中移除Size中的多个元素,对他们进行符合我们题目的一些操作。
  5. 移除每个节点时,把它们的子节点添加进Queue中。
  6. 只要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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值