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

深度优先遍历(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. Jenkins 安装的HTML Publisher Plugin 插件无法展示ant生成的JunitReport报告

    最近在做基于jenkins ant  junit 的测试持续集成,单独ant junit生成的junitreport报告打开正常,使用Jenkins的HTML Publisher Plugin 插件无 ...

  2. Android 获取系统相册中的所有图片

    Android 提供了API可获取到系统相册中的一些信息,主要还是通过ContentProvider 来获取想要的内容. 代码很简单,只要熟悉ContentProvider 就可以了. public ...

  3. H5坦克大战之【玩家控制坦克移动2】

    周一没有看圣诞大战,这几天比较忙也没有看赛后的报道,今天就先不扯NBA,随便扯扯自己.昨天在电脑里找东西的时候翻到以前兼职健身教练时的照片,思绪一下子回到学生时代,脑子久久换不过来.现在深深觉得健身和 ...

  4. 第一个移动前端开源项目-dailog

    你还在为手机上没有忙碌光标而发愁吗?你还在抱怨弹出框组件要依赖zepto/jqery吗?你还在纠结是否要自己写一套还是去网上寻找成现成的UI组件吗?YouA为你轻松解决所有烦恼.YouA是我为移动前端 ...

  5. 如何定位Oracle数据库被锁阻塞会话的根源

    首先再次明确下,数据库因为要同时保证数据的并发性和一致性,所以操作有锁等待是正常的. 只有那些长时间没有提交或回滚的事物,阻塞了其他业务正常操作,才是需要去定位处理的. 1.单实例环境 2.RAC环境 ...

  6. MyBatis基础入门--知识点总结

    对原生态jdbc程序的问题总结 下面是一个传统的jdbc连接oracle数据库的标准代码: public static void main(String[] args) throws Exceptio ...

  7. JQuery中的siblings()是什么意思

    jQuery siblings() 方法返回被选元素的所有同胞元素,并且可以使用可选参数来过滤对同胞元素的搜索. 实例演示:点击某个li标签后将其设置为红色,而其所有同胞元素去除红色样式. 1.创建H ...

  8. 文件随机读写专用类——RandomAccessFile

     RandomAccessFile类可以随机读取文件,但是在测试中并不好用;File类可以测试文件存不存在,不存在可以创建文件;FileWriter类可以对文件进行重写或者追加内容;FileReade ...

  9. 我理解的MVC

    前言 前一阶段对MVC模式及其衍生模式做了一番比较深入的研究和实践,这篇文章也算是一个阶段性的回顾和总结. 经典MVC模式 经典MVC模式中,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的 ...

  10. Lucene4.4.0 开发之排序

    排序是对于全文检索来言是一个必不可少的功能,在实际运用中,排序功能能在某些时候给我们带来很大的方便,比如在淘宝,京东等一些电商网站我们可能通过排序来快速找到价格最便宜的商品,或者通过排序来找到评论数最 ...