目录

  • 一、图的遍历概念
  • 二、深度优先搜索(DFS)
    • (一)DFS算法步骤
      • 1、邻接表DFS算法步骤
      • 2、邻接矩阵DFS算法步骤
    • (二)深度优先生成树、森林
    • (三)DFS的空间复杂度和时间复杂度
  • 三、广度优先搜索(BFS)
    • (一)BFS算法步骤
      • 1、邻接表BFS算法步骤
      • 2、邻接矩阵BFS算法步骤
    • (二)广度优先生成树、森林
    • (三)BFS的空间复杂度和时间复杂度
  • 四、DFS和BFS的应用

一、图的遍历概念

图的遍历指从图中某一顶点出发(任意一个顶点都可以作为访问的起始顶点),按照某种遍历方法,对图中所有的顶点访问一次且只访问一次。图与树不一样,其中一个顶点可能与多个顶点相连,所以需记录已访问过的顶点,当访问一个顶点后,考虑如何选取下一个要访问的顶点。

  • 图的遍历分为两种,深度优先搜索广度优先搜索,这两种方法对无向图和有向图都适用。

二、深度优先搜索(DFS)

(一)DFS算法步骤

前面文章中,讲到过二叉树的先序遍历,其实这里图的深度优先搜索(DFS)是由其推广而来的。

二叉树的先序遍历中,首先是根结点,遍历完根结点的左子树,然后再遍历完根结点的右子树,依次下去至所有结点都遍历到。

  • 图的深度优先搜索首先选取图中某一顶点vi,访问后,任意选取一个与vi邻接的顶点,且该顶点未被访问,……,继续重复该过程,直到图中所有与vi连通的顶点都被访问到;若还有顶点未被访问到,则另外选取一个未被访问的顶点再次作为起始点,重复以上步骤,继续直至图中所有结点被访问。【尽可能深地搜索一个图】

可以看出DFS算法是一个递归过程,其中需借助一个完成操作。

写出下面这个图的深度优先遍历序列:


其深度优先遍历序列为:0,4,6,9,8,7,5,3,2,1

1、邻接表DFS算法步骤

例如下面这个无向图:


该图的邻接表如下:

通过邻接表进行深度优先搜索的步骤如下(以V1为访问起始点,不唯一):
1、首先访问0,即V1,访问后标记已访问过;
2、查看V1单链表,第一个未访问的邻接顶点为2,即V3,并以V3为出发点继续深度遍历;
3、查看V3单链表,其第一个未访问的邻接顶点为6,即V7,再以V7为出发点继续深度遍历;
4、查看V7单链表,其邻接顶点为2,即V3,它已经被访问过,于是回到V3单链表,搜索下一个未被访问的邻接顶点;
5、查看V3单链表,其下一个未访问的邻接顶点为5,即V6,以V6为出发点继续深度遍历;
6、查看V6单链表,其邻接顶点为2,也是已经被访问过,于是回到V3单链表,搜索下一个未被访问的邻接顶点;
7、查看V3单链表,其邻接顶点为0,即V1,一开始被访问过,于是回到V1单链表,搜索下一个未被访问的邻接顶点;
8、查看V1单链表,其下一个未访问的邻接顶点为1,即V2,并以V2为出发点继续深度遍历;
9、查看V2单链表,其第一个未访问的邻接顶点为4,即V5,再以V5为出发点继续深度遍历;
10、查看V5单链表,其第一个未访问的邻接顶点为7,即V8,再以V8为出发点继续深度遍历;
11、查看V8单链表,其邻接顶点为4,即V5,已经被访问过,于是回到V5单链表,搜索下一个未被访问的邻接顶点;
12、查看V5单链表,其下一个未被访问的邻接顶点为1,即V2,于是回到V2单链表,搜索下一个未被访问的邻接顶点;
13、查看V2单链表,其邻接顶点为3,即V4,并以V4为出发点继续深度遍历;;
14、查看V4单链表,其邻接顶点为7,即V8,再以V8为出发点继续深度遍历;
15、查看V8单链表,其邻接顶点为3,即V4,再以V4为出发点继续深度遍历;
16、查看V4单链表,其邻接顶点为1,即V2,再以V2为出发点继续深度遍历;
17、查看V2单链表,其邻接顶点为0,即V1,再以V1为出发点继续深度遍历;
18、查看V1单链表,其邻接顶点为2,即V3,V3中已经不存在未访问的顶点,于是回到V1单链表。
19、查看V1单链表,下一个邻接顶点为1,即V2,V2中已经不存在未访问的顶点,最后回到V1单链表,遍历完成。
故该图的深度优先遍历序列为:V1、V3、V7、V6、V2、V5、V8、V4

2、邻接矩阵DFS算法步骤

通过图的邻接矩阵实现深度优先搜索,例如下面这个图(以V1为访问起始点,是唯一的):

例如,对于下面这个有向图,对其进行深度优先搜索:


其邻接矩阵如下:

1、由V1开始,如下表【第一行为回退点,第二行为深度优先搜索得到的序列】:

V1

2、通过其邻接矩阵知,访问第一行第二列的1对应的V2顶点,由于它是在V1的行中被访问到的,所以回退点为V1:

V1
V1 V2

3、由于访问了V2,即开始访问V2行,访问第二行第三列的1对应的V4顶点,由于它是在V2的行中被访问到的,所以回退点为V2:

V1 V2
V1 V2 V4

4、由于访问了V4,即开始访问V4行,访问第四行第五列的1对应的V5顶点,由于它是在V4的行中被访问到的,所以回退点为V4:

V1 V2 V4
V1 V2 V4 V5

5、由于访问了V5,即开始访问V5行,由于第五行都为0,回退到V4,由于V4行顶点都访问完,回退到V2,由于V2行顶点都访问完,回退到V1行,此时V1行还剩第一行第三列的1对应的V3顶点未访问,访问该顶点:

V1 V2 V4
V1 V2 V4 V5 V3

6、至此,访问完了图中的所有顶点,即深度优先搜索序列为V1、V2、V4、V5、V3

  • ✨对于深度优先搜索(DFS),由于基于邻接表的遍历得到的序列可能不是唯一的,即根据边的输入次序不同,从而得到的邻接表不同,从而遍历序列不一样;而基于邻接矩阵所得到的DFS遍历序列是唯一的。

(二)深度优先生成树、森林

  • 对一个连通图或非连通图进行DFS遍历后,若将在遍历过程中所经历过的顶点保留,则可以形成一棵树或森林,即深度优先生成树深度优先生成森林;另外,基于邻接表存储的深度优先生成树或深度优先生成森林也是不唯一的;而对于邻接矩阵则是唯一的。

例如,上面这个无向连通图遍历DFS遍历生成的深度优先生成树如下(基于邻接表):

例如,对于上面这个有向图进行DFS遍历:

它并不是连通图,得到的深度优先生成森林如下:

(三)DFS的空间复杂度和时间复杂度

对于一个图G=(V,E),由顶点集V和边集E组成。
1、DFS算法的空间复杂度

  • ✨由于DFS算法是一个递归算法,即递归顶点集V,通过DFS遍历的空间复杂度为O(|V|)。

2、DFS算法的时间复杂度

  • ✨时间复杂度取决于图的存储结构,若通过邻接矩阵表示图,则查找顶点的邻接顶点所需时间为O(|V|),总时间复杂度为O(|V2|)(邻接矩阵为方阵n×n);若通过邻接表表示图,则查找所有顶点的邻接顶点所需时间为O(|E|),访问顶点所需时间为O(|V|),即总时间复杂度为O(|V|+|E|)。

三、广度优先搜索(BFS)

(一)BFS算法步骤

前面文章中,讲到过二叉树的层序遍历,其实这里图的广度优先搜索(BFS)是由其推广而来的。

二叉树的层序遍历中,层次优先,当对一层的结点都遍历完后,遍历下一层,按照次序对每个结点的左、右孩子进行遍历。

  • 图的广度优先搜索中需要借助到队列来遍历,首先选取一个起始点顶点vi,访问后将其入队并标记为已访问(使用队列用于避免重复访问,存放已经访问过的各邻接顶点);当队列不为空时检查出队顶点的所有邻接顶点,访问未被访问的邻接顶点并将其入队,……,继续重复该过程,直到图中所有与vi连通的顶点都被访问到;当队列为空时跳出循环,则此时遍历完成。

可以知道BFS算法并不是递归过程,且要用到队列

1、邻接表BFS算法步骤

例如下面这个无向图:

该图的邻接表如下:

通过邻接表进行广度优先搜索的步骤如下(这里以V1为访问起始点,不唯一):
1、首先访问0,即V1,访问后标记已访问过,使其入队,然后删除当前队头结点;【V1】
2、遍历V1单链表,使其未访问的邻接顶点2、1入队并标记;【V2、V3】
3、访问队头结点1并删除,然后遍历1对应的V2单链表,使其未访问的邻接顶点4、3入队并标记;【V3、V4、V5】
4、访问队头结点2并删除,然后遍历2对应的V3单链表,使其未访问的邻接顶点6、5入队并标记;【V4、V5、V6、V7】
5、访问队头结点3并删除,然后遍历3对应的V4单链表,使其未访问的邻接顶点7入队并标记;【V5、V6、V7、V8】
6、访问队头结点4并删除,然后遍历4对应的V5单链表,该单链表中无未访问的顶点;【V6、V7、V8】
7、访问队头结点5并删除,然后遍历5对应的V6单链表,该单链表中无未访问的顶点;【V7、V8】
8、访问队头结点6并删除,然后遍历6对应的V7单链表,该单链表中无未访问的顶点;【V8】
9、访问队头结点7并删除,然后遍历7对应的V8单链表,该单链表中无未访问的顶点,此时队列为空,遍历结束;【】
故该图的深度优先遍历序列为:V1、V2、V3、V4、V5、V6、V7、V8

2、邻接矩阵BFS算法步骤

通过图的邻接矩阵实现广度优先搜索,例如下面这个图(以V1为访问起始点,是唯一的):

例如,对于下面这个有向图,对其进行广度优先搜索:


其邻接矩阵如下:

1、由V1行开始,如下表:

V1

2、可得与其匹配的有V2、V3,填到表中V1之后:

V1 V2 V3

3、由V2行开始,其中V4未访问,填到V3之后:

V1 V2 V3 V4

4、由V3行开始,都为0,继续下一行。
5、由V4行开始,其中V5未访问,填到V4之后:

V1 V2 V3 V4 V5

6、至此,该图的所有顶点都已访问到,得到的序列便是广度优先搜索,即深度优先搜索序列为V1、V2、V3、V4、V5

  • ✨同样,对于广度优先搜索,由于基于邻接表的遍历得到的序列可能不是唯一的,即根据边的输入次序不同,从而得到的邻接表不同,从而遍历序列不一样;而基于邻接矩阵所得到的遍历序列是唯一的,这两点和深度优先搜索遍历是一样的。

(二)广度优先生成树、森林

  • 与DFS遍历一样, 对一个连通图或非连通图进行BFS遍历后,若将在遍历过程中所经历过的顶点保留,则可以形成一棵树或森林,即广度优先生成树广度优先生成森林;另外,基于邻接表存储的广度优先生成树或广度优先生成森林也是不唯一的;而对于邻接矩阵则是唯一的。

例如,上面这个无向连通图遍历BFS遍历生成的深度优先生成树如下(基于邻接表):

例如,对于上面这个有向图进行BFS遍历:

它并不是连通图,得到的广度优先生成森林如下:

例如写出下面这个图的广度优先遍历序列:


其广度优先遍历序列为:0,4,3,2,1,6,5,9,8,7。

(三)BFS的空间复杂度和时间复杂度

对于一个图G=(V,E),由顶点集V和边集E组成。
1、BFS算法的空间复杂度

  • ✨通过BFS遍历的空间复杂度为O(|V|)。

2、BFS算法的时间复杂度

  • ✨时间复杂度取决于图的存储结构,若通过邻接矩阵表示图,则查找顶点的邻接顶点所需时间为O(|V|),总时间复杂度为O(|V2|)(邻接矩阵为方阵n×n),这和DFS算法的时间复杂度是一样的;若通过邻接表表示图,则每个顶点都入队一次,即所需时间为O(|V|),搜索顶点的邻接顶点所需时间为O(|E|),其时间复杂度为O(|V|+|E|)。

四、DFS和BFS的应用

以上两种遍历算法都可以用于判断图的连通性,可计算图中的连通分量数目,当一个图为连通图时,经过遍历后会访问到所有的顶点,其中访问过的顶点不会再次访问,从而可以得到图中的连通分量数目。

数据结构学习笔记——图的遍历算法(深度优先搜索和广度优先搜索)相关推荐

  1. 数据结构学习笔记------图

    主要掌握深度优先搜索与广度优先搜索的程序设计 掌握图的基本概念及基本性质(度.路径长度.回路.路径等).图的存储结构及其特性. 存储结构之间的转化.基于存储结构上的遍历操作和各种应用 (拓扑排序:AO ...

  2. 数据结构与算法学习笔记——图 C++实现

    数据结构与算法学习笔记--图 C++实现 1 概念 2 图的表示方法 3 算法 3.1 拓扑排序 3.2 图的搜索算法 3.2.1 广度优先搜索(BFS) 3.2.2 深度优先搜索(DFS) 3.3 ...

  3. 数据结构学习笔记(6)——图

    图的存储结构 图的顺序存储结构--邻接矩阵 typedef struct { int no; //顶点编号,表示它的位置char info; //顶点的其他辅助信息,没有的话可以删除 }VertexT ...

  4. Python算法学习[5]—图、遍历、连通、最短路径代码演练

    图.遍历.连通.最短路径&代码演练 图是计算机科学中的一种数据结构,它由节点(顶点)和边组成.在实际应用中,图经常被用来表示复杂系统之间的关系,如社交网络.交通网络等.本文将介绍图的基本概念和 ...

  5. 图的遍历算法【数据结构F】

    图的遍历算法有哪两种? 深度优先调度算法---------将图结构看成是树形结构,树形结构的子图直接是没有交叉的,但是对于图结构的树形结构之间是有交叉的,类比于树形结构的二叉树,左指数和右指数都会相应 ...

  6. 数据结构之图的遍历:深度优先遍历(DFS)

    图的遍历:深度优先遍历 思维导图: 深度优先遍历的原理: 深度优先遍历的代码实现: 深度优先遍历的性能: 深度优先生成树: 遍历与连通性的关系: 思维导图: 深度优先遍历的原理: ps: 实现方法是递 ...

  7. 【数据结构】图-图的遍历_深度优先遍历(动态图解、c++、java)

    文章目录 一.概述 二.深度优先搜索 算法步骤 递归 非递归 图解 BFS树 代码 邻接矩阵实现 邻接表实现 链式前向星实现 三.完整代码 邻接矩阵版 邻接表版 链式前向星版 四.总结 算法复杂度分析 ...

  8. [算法学习no7]图的遍历

    图的遍历分为两种 1.深度优先搜索 2.广度优先搜索 图的遍历难度在于图有闭环,双向 所以一定不要迷路 因此,需要用数组标记访问过的结点即可 1.深度优先搜索 传入参数为结点 输出这个结点 标记这个结 ...

  9. 数据结构学习笔记(王道)

    数据结构学习笔记(王道) PS:本文章部分内容参考自王道考研数据结构笔记 文章目录 数据结构学习笔记(王道) 一.绪论 1.1. 数据结构 1.2. 算法 1.2.1. 算法的基本概念 1.2.2. ...

最新文章

  1. java cache system_Java Cache System JCS(一) 使用方法
  2. 安全的加强的linux:SELinux
  3. java的知识点45——事务||测试时间处理(java.sql.date,time,timestamp)
  4. matlab入门之旅,MATLAB 入门之旅学习笔记
  5. 计算机有必要报英语四级吗,我已工作了,现在有必要去考英语四级吗?还是 – 手机爱问...
  6. [Lab 2] OSPF专题
  7. java语法结构库,万字解析!
  8. h5 img js 点击图片放大_jquery – HTML5 Canvas调整图像点击放大
  9. Linux下部署PHP_YAF框架
  10. excel 第六次人口普查_第六次全国人口普查表短表(标准版)
  11. Zotero使用记录----1 下载与安装
  12. Android手机安全软件的恶意程序检测靠谱吗--LBE安全大师、腾讯手机管家、360手机卫士恶意软件检测方法研究...
  13. 临床数据共享能带来什么好处?
  14. Linux--信号signal、父子进程、SIGCHLD信号相关命令
  15. python开发小程序拼团_拼团商城模式开发(如何开发)
  16. 使用Visio画各种可视化的流程图之基本流程图和跨职能流程图
  17. 免费AWS EC2实例
  18. gsoc 任务_gsoc 2020与cern hsf暗物质和深度学习
  19. 用队列模拟患者医院看病的过程
  20. Eclipse中使用SVN连接Google Code 报could not connect to server错误解决方法

热门文章

  1. MySQL性能优化配置诀窍之细水长流
  2. 用Excel如何将文本转换为数字的七种方法
  3. SVN分支创建 与 分支和主干的代码合并问题
  4. win10 20H2 下QQ,TIM 无法访问个人文件夹 个人文件夹将被保存到“我的文档
  5. Spring - 手把手分析 IoC 容器创建过程
  6. python单机五子棋详解(tkinter)
  7. Lesson 24 PropTypes 和组件参数验证
  8. android应用程序设计大作业,Android实验大作业
  9. 链化未来跨链与波卡跨链对比解析
  10. 人工智能在线AI智能模型聊天AI网站系统源码