图的遍历的定义:
从图的某个顶点出发访问遍图中所有顶点,且每个顶点仅被访问一次。(连通图与非连通图)

深度优先遍历(DFS);

1、访问指定的起始顶点;

2、若当前访问的顶点的邻接顶点有未被访问的,则任选一个访问之;反之,退回到最近访问过的顶点;直到与起始顶点相通的全部顶点都访问完毕;

3、若此时图中尚有顶点未被访问,则再选其中一个顶点作为起始顶点并访问之,转 2; 反之,遍历结束。

连通图的深度优先遍历类似于树的先根遍历

如何判别V的邻接点是否被访问?

解决办法:为每个顶点设立一个“访问标志”。首先将图中每个顶点的访问标志设为 FALSE,  之后搜索图中每个顶点,如果未被访问,则以该顶点为起始点,进行深度

优先遍历,否则继续检查下一顶点。

 
访问指定的起始顶点;若当前访问的顶点的邻接顶点有未被访问的,则任选一个访问之;
反之,退回到最近访问过的顶点;直到与起始顶点相通的全部顶点都访问完毕;
 
回退到1,发现了新的没有被访问的结点
继续回退,回退到0
再也找不到新的结点了,那么回退,回退到起始顶点,结束搜索

顶点的访问序列为:    v0 , v1 , v4 , v5 , v6 , v2 , v3(不唯一)

实现过程:依靠栈,一维数组和图的邻接矩阵存储方式

图的邻接矩阵存储方式
 
使用一个一维数组存储所有的顶点,对应的下标的元素为1(代表已经被访问),0(代表没有被访问)
 
先访问 v1,0进栈,0处置为1
 
继续访问 v2,1进栈,1处置为1
 
继续访问v4(依据邻接矩阵),3入栈,3处置为1
 
继续访问 v8,7入栈,7处置为1
 
继续访问 v5,4入栈,4处置为1
 
继续访问,发现没有还没访问的结点了,那么好,退栈(也就是回退)开始,回退到 v1处,也就是0的时候,发现了没有被访问的结点,那么继续访问之

继续访问 v3,2进栈,2处置为1,继续访问v6,5进栈,5处置为1,继续访问v7,6进栈,6处置为1
 
发现没有还没被访问的结点了,那么好,继续回退(也就是退栈的过程)
 
 
一直到栈空,说明深度优先搜索完毕。结束程序。

遍历图的过程实质上是对每个顶点查找其邻接点的过程,所耗费的时间取决于所采用的存储结构。
对图中的每个顶点至多调用1次DFS算法,因为一旦某个顶点已访问过,则不再从它出发进行搜索。

邻接链表表示:查找每个顶点的邻接点所需时间为O(e),e为边(弧)数,算法时间复杂度为O(n+e)

数组表示:查找每个顶点的邻接点所需时间为O(n2),n为顶点数,算法时间复杂度为O(n2)

代码如下

//访问标志数组
int visited[MAX] = {}; //用邻接表方式实现深度优先搜索(递归方式)
//v 传入的是第一个需要访问的顶点
void DFS(MGraph G, int v)
{
//图的顶点的搜索指针
ArcNode *p;
//置已访问标记
visited[v] = ;
//输出被访问顶点的编号
printf("%d ", v);
//p指向顶点v的第一条弧的弧头结点
p = G.vertices[v].firstarc;
while (p != NULL)
{
//若p->adjvex顶点未访问,递归访问它
if (visited[p->adjvex] == )
{
DFS(G, p->adjvex);
}
//p指向顶点v的下一条弧的弧头结点
p = p->nextarc;
}
}

广度优先搜索(BFS)

方法:从图的某一结点出发,首先依次访问该结点的所有邻接顶点 Vi1, Vi2, …, Vin 再按这些顶点被访问的先后次序依次访问与它们相邻接的所有未被访问的顶点,重复此过程,直至所有顶点均被访问为止。

顶点的访问次序

实现过程:依靠队列和一维数组来实现

 #include <iostream>
#include<queue>
using namespace std; const int MAX = ;
//辅助队列的初始化,置空的辅助队列Q,类似二叉树的层序遍历过程
queue<int> q;
//访问标记数组
bool visited[MAX];
//图的广度优先搜索算法
void BFSTraverse(Graph G, void (*visit)(int v))
{
int v = ;
//初始化访问标记的数组
for (v = ; v < G.vexnum; v++)
{
visited[v] = false;
}
//依次遍历整个图的结点
for (v = ; v < G.vexnum; v++)
{
//如果v尚未访问,则访问 v
if (!visited[v])
{
//把 v 顶点对应的数组下标处的元素置为真,代表已经访问了
visited[v] = true;
//然后v入队列,利用了队列的先进先出的性质
q.push(v);
//访问 v,打印处理
cout << q.back() << " ";
//队不为空时
while (!q.empty())
{
//队头元素出队,并把这个出队的元素置为 u,类似层序遍历
Graph *u = q.front();
q.pop();
//w为u的邻接顶点
for (int w = FirstAdjVex(G, u); w >= ; w = NextAdjVex(G,u,w))
{
//w为u的尚未访问的邻接顶点
if (!visited[w])
{
visited[w] = true;
//然后 w 入队列,利用了队列的先进先出的性质
q.push(w);
//访问 w,打印处理
cout << q.back() << " ";
}//end of if
}//end of for
}//end of while
}//end of if
}// end of for
}

欢迎关注

dashuai的博客是终身学习践行者,大厂程序员,且专注于工作经验、学习笔记的分享和日常吐槽,包括但不限于互联网行业,附带分享一些PDF电子书,资料,帮忙内推,欢迎拍砖!

图的遍历(搜索)算法(深度优先算法DFS和广度优先算法BFS)的更多相关文章

  1. 图的 储存 深度优先(DFS)广度优先(BFS)遍历

    图遍历的概念: 从图中某顶点出发访遍图中每个顶点,且每个顶点仅访问一次,此过程称为图的遍历(Traversing Graph).图的遍历算法是求解图的连通性问题.拓扑排序和求关键路径等算法的基础.图的 ...

  2. 洛谷 P3916 【图的遍历】反向加边+dfs

    前言: 对于这类带环的图,一般记忆化搜索不能很好的对所有遍历的边进行更新取值.因为环上的点可以相互到达,所以他们的答案因当是同步更新的,而dfs一旦你回溯完环上某个点就不会在更新这个点的答案了,做不到 ...

  3. [ACM训练] 算法初级 之 搜索算法 之 广度优先算法BFS (POJ 3278+1426+3126+3087+3414)

    BFS算法与树的层次遍历很像,具有明显的层次性,一般都是使用队列来实现的!!! 常用步骤: 1.设置访问标记int visited[N],要覆盖所有的可能访问数据个数,这里设置成int而不是bool, ...

  4. C++编程练习(9)----“图的存储结构以及图的遍历“(邻接矩阵、深度优先遍历、广度优先遍历)

    图的存储结构 1)邻接矩阵 用两个数组来表示图,一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中边或弧的信息. 2)邻接表 3)十字链表 4)邻接多重表 5)边集数组 本文只用代码实现用 ...

  5. C# 遍历文件夹非递归实现(采用队列的广度优先算法)(转)

    一.实现思路: 1. 创建一个队列(使用C# 队列类 Queue,需要使用命名空间 System.Collections.Generic): 2. 把起始文件夹名称排入队中: 3. 检查队列中是否有文 ...

  6. 图的深度优先搜索(DFS)和广度优先搜索(BFS)算法

    深度优先(DFS) 深度优先遍历,从初始访问结点出发,我们知道初始访问结点可能有多个邻接结点,深度优先遍历的策略就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接 ...

  7. 图的存储,搜索,遍历,广度优先算法和深度优先算法,最小生成树-Java实现

    1)用邻接矩阵方式进行图的存储.如果一个图有n个节点,则可以用n*n的二维数组来存储图中的各个节点关系. 对上面图中各个节点分别编号,ABCDEF分别设置为012345.那么AB AC AD 关系可以 ...

  8. 图的遍历算法:DFS、BFS

    在图的基本算法中,最初需要接触的就是图的遍历算法,根据访问节点的顺序,可分为深度优先搜索(DFS)和广度优先搜索(BFS). DFS(深度优先搜索)算法 Depth-First-Search 深度优先 ...

  9. 算法学习笔记(六) 二叉树和图遍历—深搜 DFS 与广搜 BFS

    图的深搜与广搜 复习下二叉树.图的深搜与广搜. 从图的遍历说起.图的遍历方法有两种:深度优先遍历(Depth First Search), 广度优先遍历(Breadth First Search),其 ...

随机推荐

  1. CMS模板应用调研问卷

    截止目前,已经有数十家网站与我们合作,进行了MIP化改造,在搜索结果页也能看到"闪电标"的出现.除了改造方面的问题,MIP项目组被问到最多的就是:我用了wordpress,我用了织 ...

  2. SQL:指定名称查不到数据的衍伸~空格 换行符 回车符的批量处理

    异常处理汇总-数据库系列  http://www.cnblogs.com/dunitian/p/4522990.html 先看看啥情况 复制查询到的数据,粘贴一下看看啥情况 那就批量处理一下~ 就这样 ...

  3. 通过三次优化,我将gif加载优化了16.9%

    WeTest 导读 现在app越来越炫,动不动就搞点动画,复杂的动画用原生实现起来挺复杂,如是就搞起gif播放动画的形式,节省开发成本.   背 景 设计同学准备给一个png序列,开发读取png序列, ...

  4. .Net 分布式云平台基础服务建设说明概要

    1)  背景 建设云平台的基础框架,用于支持各类云服务的业务的构建及发展. 2)  基础服务 根据目前对业务的理解和发展方向,总结抽象出以下几个基础服务,如图所示 3)  概要说明 基础服务的发展会根 ...

  5. 关于Android避免按钮重复点击事件

    最近测试人员测试我们的APP的时候,喜欢快速点击某个按钮,出现一个页面出现多次,测试人员能不能禁止这样.我自己点击了几下,确实存在这个问题,也感觉用户体验不太好.于是乎后来我搜了下加一个方法放在我们U ...

  6. 用游标实现查询当前服务器所有数据库所有表的SQL

    declare @name varchar(100) DECLARE My_Cursor CURSOR --定义游标 FOR (SELECT Name FROM Master..SysDatabase ...

  7. Oracle中的commit详解

    本文转自 : http://blog.csdn.net/hzhsan/article/details/9719307 它执行的时候,你不会有什么感觉.commit在数据库编程的时候很常用,当你执行DM ...

  8. liunx 磁盘管理命令记录

    Linux磁盘管理好坏管理直接关系到整个系统的性能问题. Linux磁盘管理常用三个命令为df.du和fdisk. df:列出文件系统的整体磁盘使用量 du:检查磁盘空间使用量 fdisk:用于磁盘分 ...

  9. PHP安装

    工具 http://www.cnblogs.com/xiwang6428/p/4315049.html http://www.iteye.com/news/22672 1 安装:sudo apt-ge ...

  10. emmet,jade,haml, slim,less,sass,coffeescript等的实战优缺点

    摘要: 文章背景,来自于群内周五晚上的一次头脑风暴式的思维碰撞交流活动. 随着前端技术的蓬勃发展, 各种新技术随着生产力的需要不断的涌入我们的视野, 那今天探讨的话题是这些新时代的前端兵器谱: 一. ...