【数据结构与算法】BFS 和 DFS
创始人
2024-01-25 05:13:03
0

🔥 本文由 程序喵正在路上 原创,CSDN首发!
💖 系列专栏:数据结构与算法
🌠 首发时间:2022年11月16日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾
🌟 一以贯之的努力 不得懈怠的人生

阅读指南

  • 基本操作
  • 广度优先遍历(BFS)
    • 与树的广度优先遍历之间的联系
    • 算法实现
    • 复杂度分析
    • 广度优先生成树
  • 深度优先遍历(DFS)
    • 与树的深度优先遍历之间的联系
    • 算法实现
    • 复杂度分析
    • 深度优先遍历序列
    • 深度优先生成树
    • 图的遍历和图的连通性

基本操作

  • Adjacent(G,x,y)Adjacent(G, x, y)Adjacent(G,x,y):判断图 GGG 是否存在边 或 (x,y)(x, y)(x,y)
  • Neighbors(G,x)Neighbors(G, x)Neighbors(G,x):列出图 GGG 中与结点 xxx 邻接的边
  • InsertVertex(G,x)InsertVertex(G, x)InsertVertex(G,x):在图 GGG 中插入顶点 xxx
  • DeleteVertex(G,x)DeleteVertex(G, x)DeleteVertex(G,x):在图 GGG 中删除顶点 xxx
  • AddEdge(G,x,y)AddEdge(G, x, y)AddEdge(G,x,y):若无向边 (x,y)(x, y)(x,y) 或有向边 不存在,则向图 GGG 中添加该边
  • RemoveEdge(G,x,y)RemoveEdge(G, x, y)RemoveEdge(G,x,y):若无向边 (x,y)(x, y)(x,y) 或有向边 存在,则从图 GGG 中删除该边
  • FirstNeighbor(G,x)FirstNeighbor(G, x)FirstNeighbor(G,x):求图 GGG 中顶点 xxx 的第一个邻接点,若有则返回顶点号;若 xxx 没有邻接点或图中不存在 xxx,则返回 −1-1−1
  • NextNeighbor(G,x,y)NextNeighbor(G, x, y)NextNeighbor(G,x,y):假设图 GGG 中顶点 yyy 是顶点 xxx 的一个邻接点,返回除了 yyy 之外顶点 xxx 的下一个邻接点的顶点号,若 yyy 是 xxx 的最后一个邻接点,则返回 −1-1−1
  • Getedgevalue(G,x,y)Get_edge_value(G, x, y)Gete​dgev​alue(G,x,y):获取图 GGG 中边 (x,y)(x, y)(x,y) 或 对应的权值
  • Setedgevalue(G,x,y,v)Set_edge_value(G, x, y, v)Sete​dgev​alue(G,x,y,v):设置图 GGG 中边 (x,y)(x, y)(x,y) 或 对应的权值为 vvv

广度优先遍历(BFS)

与树的广度优先遍历之间的联系

树的广度优先遍历,也就是树的层次遍历,有以下步骤:

  1. 若树非空,则根节点入队
  2. 若队列非空,队头元素出队并访问,同时将该元素的孩子依次入队
  3. 重复第 222 步指导队列为空

对于树,由于树不存在 “回路”,因此在搜索相邻的结点时,不可能搜索到已经访问过的结点;而图则反之,所以我们需要对图中的结点进行标记,以此来识别这个结点是否访问过

广度优先遍历(Breadth−First−Search,BFSBreadth-First-Search, BFSBreadth−First−Search,BFS)要点:

  1. 找到与一个顶点相邻的所有顶点
  2. 标记哪些顶点被访问过
  3. 需要一个辅助队列

在广度优先遍历中,我们需要用到两个基本操作:

  • FirstNeighbor(G,x)FirstNeighbor(G, x)FirstNeighbor(G,x):求图 GGG 中顶点 xxx 的第一个邻接点,若有则返回顶点号;若 xxx 没有邻接点或图中不存在 xxx,则返回 −1-1−1
  • NextNeighbor(G,x,y)NextNeighbor(G, x, y)NextNeighbor(G,x,y):假设图 GGG 中顶点 yyy 是顶点 xxx 的一个邻接点,返回除了 yyy 之外顶点 xxx 的下一个邻接点的顶点号,若 yyy 是 xxx 的最后一个邻接点,则返回 −1-1−1

算法实现

bool visited[MAX_VERTEX_NUM];	//访问标记数组,初始值都为falsevoid BFSTraverse(Graph G) {		//对图G进行广度优先遍历for (i = 0; i < G.vexnum; ++i) {visited[i] = false;		//访问标记数组初始化}InitQueue(Q);				//初始化辅助队列Qfor (i = 0; i < G.vexnum; ++i) {	//从0号顶点开始遍历if (!visited[i]) 				//对每个连通分量调用一次BFSBFS(G, i);					//vi未访问过,从vi开始BFS}
}//广度优先遍历
void BFS(Graph G, int v) {		//从顶点v出发,广度优先遍历图visit(v);					//访问初始顶点vvisited[v] = true;			//对v做已访问标记Enqueue(Q, v);				//顶点v入队列Qwhile (!isEmpty(Q)) {DeQueue(Q, v);			//顶点v出队for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)) {//检测v所有邻接点if (!visited[w]) {				//w为v的未访问过的邻接顶点visit(w);					//访问顶点wvisited[w] = true;			//对w做已访问标记Enqueue(Q, w);				//顶点w入队列Q}//if}//for}//while
}	

结论:对于无向图,调用 BFSBFSBFS 函数的次数 === 连通分量数(连通分量:一个极大连通子图为一个连通分量)

复杂度分析

空间复杂度:

  • 最坏情况,我们访问第一个顶点时,所有顶点都和它连通,此时辅助队列大小为 O(∣V∣)O(|V|)O(∣V∣)

如果我们是用邻接矩阵存储的图:

在这里插入图片描述

  • 访问 ∣V∣|V|∣V∣ 个顶点需要 O(∣V∣)O(|V|)O(∣V∣) 的时间
  • 查找每个顶点的邻接点都需要 O(∣V∣)O(|V|)O(∣V∣) 的时间,而总共有 ∣V∣|V|∣V∣ 个顶点
  • 时间复杂度 =O(∣V∣2)= O(|V|^2)=O(∣V∣2)

如果我们是用邻接表存储的图:
在这里插入图片描述

  • 访问 ∣V∣|V|∣V∣ 个顶点需要 O(∣V∣)O(|V|)O(∣V∣) 的时间
  • 查找每个顶点的邻接点共需要 O(∣E∣)O(|E|)O(∣E∣) 的时间
  • 时间复杂度 =O(∣V∣+∣E∣)= O(|V| + |E|)=O(∣V∣+∣E∣)

广度优先生成树

在这里插入图片描述

广度优先生成树由广度优先遍历过程确定。由于邻接表的表示方式不唯一,因此基于邻接表的广度优先生成树也不唯一

对于非连通图的广度优先遍历,我们还可以得到广度优先生成森林

深度优先遍历(DFS)

与树的深度优先遍历之间的联系

树的深度优先遍历分为先根遍历和后根遍历,图的深度优先遍历和树的先根遍历比较相似

//树的先根遍历
void PreOrder(TreeNode *R) {if (R != NULL) {visit(R);		//访问根节点while (R还有下一个子树T)PreOrder(T);	//先根遍历下一棵子树}
}

算法实现

bool visited[MAX_VERTEX_NUM];	//访问标记数组void DFSTraverse(Graph G) {				//对图G进行深度优先遍历for (v = 0; v < G.vexnum; ++v)		//初始化已访问标记数据visited[v] = false;for (v = 0; v < G.vexnuj; ++v)		//解决非连通图无法遍历完的问题if (!visited[v]) DFS(G, v);
}void DFS(Graph G, int v) {		//从顶点v出发,深度优先遍历图Gvisit(v);					//访问顶点vvisited[v] = true;			//设置已访问标记for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)) {if (!visited[w]) {		//w为v的未访问的邻接顶点DFS(G, w);}}
}

复杂度分析

空间复杂度:来自函数调用栈,最坏情况下,递归深度为 O(∣V∣)O(|V|)O(∣V∣);最好情况为 O(1)O(1)O(1)

时间复杂度 === 访问每个节点所需时间 +++ 探索每条边所需时间

如果是用邻接矩阵存储的图:

  • 访问 ∣V∣|V|∣V∣ 个顶点需要 O(∣V∣)O(|V|)O(∣V∣) 的时间
  • 查找每个顶点的邻接点都需要 O(∣V∣)O(|V|)O(∣V∣) 的时间,总共有 ∣V∣|V|∣V∣ 个顶点
  • 总时间复杂度为 O(∣V∣2)O(|V|^2)O(∣V∣2)

如果是用邻接表存储的图:

  • 访问 ∣V∣|V|∣V∣ 个顶点需要 O(∣V∣)O(|V|)O(∣V∣) 的时间
  • 查找每个顶点的邻接点共需要 O(∣E∣)O(|E|)O(∣E∣) 的时间
  • 时间复杂度 =O(∣V∣+∣E∣)= O(|V| + |E|)=O(∣V∣+∣E∣)

你会发现,深度优先遍历和广度优先遍历的复杂度是一样的

深度优先遍历序列

在这里插入图片描述

对于上图:

  • 从 111 出发的深度优先遍历序列为:1,2,6,3,4,7,8,51, 2, 6, 3, 4, 7, 8, 51,2,6,3,4,7,8,5
  • 从 222 出发的深度优先遍历序列为:2,1,5,6,3,4,7,82, 1, 5, 6, 3, 4, 7, 82,1,5,6,3,4,7,8
  • 从 333 出发的深度优先遍历序列为:3,4,7,6,2,1,5,83, 4, 7, 6, 2, 1, 5, 83,4,7,6,2,1,5,8

注意:如果邻接表不一样,深度优先遍历序列也可能不一样;同时,因为邻接矩阵表示方式唯一,所以深度优先遍历序列唯一

深度优先生成树

将深度优先遍历序列写成树的形式,即为对应的深度优先生成树

如果是非连通图,那么会有深度优先生成森林

图的遍历和图的连通性

对无向图进行 BFS/DFSBFS/DFSBFS/DFS 遍历,调用 BFS/DFSBFS/DFSBFS/DFS 函数的次数等于连通分量数;如果是连通图的话,我们只需要调用一次 BFS/DFSBFS/DFSBFS/DFS 函数

对有向图进行 BFS/DFSBFS/DFSBFS/DFS 遍历,调用 BFS/DFSBFS/DFSBFS/DFS 函数的次数要根据具体的数进行具体分析;如果起始顶点到其他顶点都有路径,那么我们只需要调用一次函数即可

对于强连通图,我们从任何一个顶点出发都只需要调用一次 BFS/DFSBFS/DFSBFS/DFS

在这里插入图片描述

相关内容

热门资讯

小学二年级数学日记 [小学二年级数学日记]更多作文 > 日记 小学二年级数学日记 第一篇:小学二年级数学日记一-...
小猫观察日记小学 小猫观察日记小学7篇小猫观察日记小学1  20xx月X日 星期X 晴  我养了一只小猫,有些白,有些...
绿豆的发芽的实验周记 绿豆的发芽的实验周记  时光匆匆,一个星期已经结束了,这一周内让你有什么启发呢?是时候仔细地写一篇周...
吊兰的观察日记 吊兰的观察日记吊兰的观察日记1  吊兰是一种常见的植物。今天我就买了一盆吊兰,经过了几天的相处,我已...
清明节日记 关于清明节日记(通用28篇)  一天的时间眼看就要结束了,这一天里,大家身边一定有一些有趣的见闻吧,...
夏令营小学日记 夏令营小学日记  8月18日上午晴  游中华恐龙园  经过4个小时的漫长车程,我们真有点头晕目眩,虽...
黄豆发芽的日记 黄豆发芽的日记  相信所有人都吃过豆芽,只是很多人还不知道如何把黄豆变成黄豆芽,实际上这个过程很简单...
童年读书笔记 童年读书笔记(通用5篇)  读完一本书以后,相信大家的收获肯定不少,需要回过头来写一写读书笔记了。现...
的记事日记 的记事日记范文9篇的记事日记 篇1  姥姥家养了很多鸟。有画眉、白灵、还有鹩哥。我最喜欢的就是那只巧...
一次难忘的活动小学日记 一次难忘的活动小学日记  星期一的时候,老师宣布了一个振奋人心的消息:星期五,我们要去射阳参加素质教...
《昆虫记》读书笔记 《昆虫记》读书笔记(通用20篇)  当赏读完一本名著后,相信大家都积累了属于自己的读书感悟,现在就让...
滑雪小学日记 滑雪小学日记  今天,我和舅舅一起来到了玉黛湖。因为我们要去雪。我们先找到了交钱的地方,交上钱和20...
小学观察日记 【必备】小学观察日记四篇小学观察日记 篇1  今天是国庆节,我要去完成曹老师布置的“豆子观察日记”的...
日常日记 日常日记范文(通用20篇)  忙碌而又充实的一天又过去了,我们对人和事情也有了新的看法,需要认真地为...
小学生六年级日记 小学生六年级日记(通用39篇)  不知不觉中一天又要结束了,这一天里,有没有哪件事或某个人触动到我们...
空间伤感日记 空间伤感日记(精选32篇)  一天即将过去了,在你心中有什么感想呢?需要认真地为此写一篇日记了。那么...
终是过往成空的作文450字 终是过往成空的作文450字  “明天你是否会想起,昨天你写的日记,明天你是否会惦记,曾经最爱哭的你…...
我的拉纤经历心情日记 我的拉纤经历心情日记  转眼当海军已经七年了。先是在舰艇上当战士,然后到院校学习。几年之间走南闯北也...
发豆芽优秀作文 发豆芽优秀作文  20xx年1月18日周六多云  这个暑假,老师给我们布置了一个十分有趣的作业——发...
大班绘本:蚯蚓的日记 大班绘本:蚯蚓的日记  一天将要结束了,这一天里,有没有哪件事或某个人触动到我们呢?这时候十分有必须...