深度和广度优先遍历

文章介绍了图的深度优先搜索(DFS)和广度优先搜索(BFS)的概念及遍历过程。DFS类似于树的前序遍历,而BFS则类似层级遍历。DFS策略是尽可能深地搜索,而BFS则保证先访问最近的节点。文章还提到了回溯边界定制和剪枝策略以提高搜索效率。
摘要由CSDN通过智能技术生成

前言

图的遍历与树的遍历相似,也是从某个顶点出发,沿着某条搜索路径对图的每个顶点做且仅做一次访问。

深度优先搜索遍历(Depth First Search,DFS)

深度优先遍历类似于树的前序遍历,选则任意一个顶点v作为初始出发点,首先访问出发点v并将其标记为已访问过;然后搜索v的每个邻接点w。若w未被访问,则从w开始出发继续进行深度优先遍历(即继续访问w的邻接点),直到所有与v路径相同的结点都访问到;若此时图中仍有顶点没被访问,就选则没被访问的顶点开始出发,重复以上步骤,直至图中所有顶点访问完。

则图1的深度优先遍历的顶点访问序列为:a,b,d,h,e,c,f,g

图1

对图进行深度优先遍历时,按访问顶点的先后次序得到的顶点序列称为图的深度优先遍历序列,或简称为DFS序列

广度优先搜索遍历(Breadth First Search,BFS)

广度优先搜索遍历类似于树的按层级遍历。

其基本思想就是:首先访问出发点v,接着访问v的所有未被访问过的邻接点v1,v2...,并将其标记为已访问过,在依次访问v1,v2...的邻接点并标记,以此类推;直至所有顶点都被访问到。

那么图1的以a为出发点的广义优先搜索遍历序列为:a,b,c,d,e,f,g,h

在广度优先遍历中,先被访问的顶点,其邻接点也先被访问,即符合队列的性质:先进先出。

图2

(a)

图2的邻接矩阵为a,以4为出发结点的两种遍历序列如下:

DFS:4,1,2,0,3

BFS:4,0,1,3,2

总结

如算法名称那样,深度优先搜索所遵循的搜索策略是尽可能“深”地搜索树。它的基本思想是:为了求得问题的解,先选择某一种可能情况向前(子结点)探索,在探索过程中,一旦发现原来的选择不符合要求,就回溯至父亲结点重新选择另一结点,继续向前探索,如此反复进行,直至求得最优解。

  1. 减少节点数,思想:尽可能减少生成的节点数

  1. 定制回溯边界,思想:定制回溯边界条件,剪掉不可能得到最优解的子树

在很多情况下,我们已经找到了一组比较好的解。但是计算机仍然会义无返顾地去搜索比它更“劣”的其他解,搜索到后也只能回溯。为了避免出现这种情况,我们需要灵活地去定制回溯搜索的边界。

在深度优先搜索的过程当中,往往有很多走不通的“死路”。假如我们把这些“死路”排除在外,不是可以节省很多的时间吗?打一个比方,前面有一个路径,别人已经提示:“这是死路,肯定不通”,而你的程序仍然很“执着”地要继续朝这个方向走,走到头来才发现,别人的提示是正确的。这样,浪费了很多的时间。针对这种情况,我们可以把“死路”给标记一下不走,就可以得到更高的搜索效率。

对于状态数很多时,广度优先搜索可以采用循环队列或动态链表来处理,对于这两种搜索算法,其主要区别如下表:

遍历方式

深度优先搜索遍历

广度优先搜索遍历

所用数据结构

队列

一般优化

最优性剪枝

可行性剪枝

Hash判重

双向搜索

以下是图的深度优先遍历广度优先遍历的C语言实现: 深度优先遍历: ```c #include<stdio.h> #define MAX 100 int visited[MAX]; //记录节点是否被访问 int G[MAX][MAX]; //邻接矩阵表示图 int n; //节点数 void DFS(int i) { int j; visited[i] = 1; printf("%d ",i); //输出节点i的值 for(j=0;j<n;j++) { if(!visited[j] && G[i][j]==1) //如果节点j未被访问且与节点i相邻 DFS(j); //递归访问节点j } } void DFSTraverse() { int i; for(i=0;i<n;i++) visited[i] = 0; //初始化visited数组 for(i=0;i<n;i++) { if(!visited[i]) //如果节点i未被访问 DFS(i); //从节点i开始深度优先遍历 } } int main() { int i,j; printf("请输入节点数:"); scanf("%d",&n); printf("请输入邻接矩阵:\n"); for(i=0;i<n;i++) for(j=0;j<n;j++) scanf("%d",&G[i][j]); printf("深度优先遍历结果:"); DFSTraverse(); return 0; } ``` 广度优先遍历: ```c #include<stdio.h> #define MAX 100 int visited[MAX]; //记录节点是否被访问 int G[MAX][MAX]; //邻接矩阵表示图 int n; //节点数 void BFS(int i) { int queue[MAX],head=0,tail=0; int j,k; printf("%d ",i); //输出节点i的值 visited[i] = 1; queue[tail++] = i; //将节点i入队 while(head<tail) //队列不为空 { j = queue[head++]; //队头元素出队 for(k=0;k<n;k++) { if(!visited[k] && G[j][k]==1) //如果节点k未被访问且与节点j相邻 { printf("%d ",k); //输出节点k的值 visited[k] = 1; queue[tail++] = k; //将节点k入队 } } } } void BFSTraverse() { int i; for(i=0;i<n;i++) visited[i] = 0; //初始化visited数组 for(i=0;i<n;i++) { if(!visited[i]) //如果节点i未被访问 BFS(i); //从节点i开始广度优先遍历 } } int main() { int i,j; printf("请输入节点数:"); scanf("%d",&n); printf("请输入邻接矩阵:\n"); for(i=0;i<n;i++) for(j=0;j<n;j++) scanf("%d",&G[i][j]); printf("广度优先遍历结果:"); BFSTraverse(); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值