图——深度优先遍历(DFS)实现有向无环图的逆拓扑排序
对图的深度遍历与对树的深度遍历思想类似,采用的是递归函数的办法。
如果是非连通图,则DFS遍历所有顶点即可。
//Graph 图
//vertex 顶点,用一个int型变量表示//返回有向图G中顶点v的第一个邻接点,如没有返回-1
int FirstNeighbor(Graph G, int v)
{//(......具体实现细节)return w;
}//假设图G中w是v的一个邻接点,返回除w外的v的下一个邻接点,若没有,返回-1
int NextNeighbor(Graph G, int v, int w)
{//(......具体实现细节)return w;
}//访问v顶点
void visit(int v);//标记顶点被访问状态的数组,初始时全为false
bool visited[MAX_NUM];//从图G中的顶点v开始进行深度优先遍历,是递归函数
void DFS(Graph G, int v)
{visit(v);visited[v] = true; //顶点v已被访问for (w = FirstNeighbor(G, v); w != -1; w = NextNeighbor(G, v, w)){if (visited[w] == false)DFS(G, w);}
}
对于有向无环图,则肯定是非强连通的,需遍历所有顶点。
拓扑排序:有向无环图的一种排序,若图中有A指向B的路径,则排序中A一定在B的前面。一个有向无环图可能存在多种拓扑排序。
下图表示“吃番茄炒蛋”的过程,可以有多种途径吃上番茄炒蛋,但无论哪种途径,必须先买菜再打鸡蛋、先准备厨具再切番茄等等。任何一种能“吃上鸡蛋”的过程就是下图的一个拓扑排序。
图来源:b站王道计算机考研 数据结构 P66
每一种拓扑排序都存在其对应的逆拓扑排序,将排序反向即可。
倘若要逆拓扑排序输出一个图,则可采用DFS算法。
//初始时默认visited数组全为false//为保证所有顶点都被排序,需遍历所有顶点
for (int i = 0; i < MAX_NUM; i++){if (!visited[i])DFS(G, i);
}void DFS(Graph G, int v){visited[v] = true;for (w = FirstNeighbor(G, v); w != -1; w = NextNeighbor(G, v, w)){if (!visited[w])DFS(G, w);}print(v); //输出v信息进行逆拓扑排序
}
原理:无论从任何顶点v开始DFS,DFS递归函数运行时会存在函数调用栈,最先执行结束的那一层函数是某条路上最深的那个顶点,结束之前将其输出排序,这样v为起点的这条路径(包括有分路的情况,但分路的先后顺序没有要求)上所有顶点就都被“反向输出”了。
再遍历其他顶点w时,要么w与v不存在路径,要么一定是有w指向v的路径,因为如果v存在指向w的路径,DFS(v)过程中一定会输出w,visited[w] == false,DFS对w也不会生效了。
所以上述输出一定可以满足逆拓扑排序要求。
question:如果图是存在环的,上述算法会失效。如下:
如果DFS(G, 0),会输出2 4 3 1 0。但有环图根本不存在逆拓扑排序。(有环代表永远输出不完,无拓扑,更不谈逆拓扑),所以需要修改DFS内容来判断是否存在环。
方法:从新设置一个数组 if_visiting[MAX_NUM] 记录该顶点是否正处于被访问状态
//初始时默认visited数组、if_visiting数组全为false//为保证所有顶点都被排序,需遍历所有顶点
for (int i = 0; i < MAX_NUM; i++){if (!visited[i])DFS(G, i);
}void DFS(Graph G, int v){visited[v] = true;if_visiting[v] = true;for (w = FirstNeighbor(G, v); w != -1; w = NextNeighbor(G, v, w)){if (!visited[w]){DFS(G, w);}if (if_visiting[w]){cout << "存在回路" <<endl;return;}}print(v); //输出v信息进行逆拓扑排序if_visiting[v] = false;
}
在visit一个顶点v之后,将其if_visiting也设为true,这样往下遍历时如果有顶点的下一个顶点为v,就会检测到v正在被访问,于是存在环路。可以输出提示我们一下。
print完v之后,if_visiting重新设为false,代表v顶点彻底被遍历完了,这样从其他路径遇到v时也不会有任何影响。
图——深度优先遍历(DFS)实现有向无环图的逆拓扑排序相关推荐
- java 有向无环图_数据调度系统中有向无环图的无环检测
点击上方蓝字关注DolphinScheduler(海豚调度) |作者:鲍亮 |编辑:卢凯瑞 1 名词解释 DAG,全称:Directed Acyclic Graph,中文:有向无环图 入度:有向图中某 ...
- 大数据工作流任务调度--有向无环图(DAG)之拓扑排序
拓扑排序(Topological Sorting) 回顾基础知识: 1.图的遍历: 图的遍历是指从图中的某一个顶点出发,按照某种搜索方法沿着图中的边对图中的所有顶点访问一次且仅访问一次.注意树是一种特 ...
- The King’s Problem(tarjan求强连通分量缩点+匈牙利求有向无环图的最小路径覆盖)
Link:http://acm.hdu.edu.cn/showproblem.php?pid=3861 The King's Problem Time Limit: 2000/1000 MS (Jav ...
- 数据调度系统中有向无环图的无环检测
数据调度系统中有向无环图的无环检测 名词解释 DAG,全称:Directed Acyclic Graph,中文:有向无环图 入度:有向图中某点作为图中边的终点的次数之和 出度: 对于有向图来说,顶点的 ...
- 笔记:深度学习与有向无环图SVM结合用于年龄估计的局部调整
阅读论文:Combined Deep Learning With Directed Acyclic Graph SVM for Local Adjustment of Age Estimation | ...
- 数据结构与算法(7-2)图的遍历(深度优先遍历DFS、广度优先遍历BFS)(分别用邻接矩阵和邻接表实现)
目录 深度优先遍历(DFS)和广度优先遍历(BFS)原理 1.自己的原理图 2.官方原理图 一.邻接矩阵的深度优先遍历(DFS) 1.原理图 2. 过程: 3.总代码 二.邻接表的深度优先遍历(DFS ...
- 图的深度优先遍历DFS(JAVA)
图的深度优先遍历算法 在此介绍图的基本算法之一的深度优先遍历(DFS)算法 广度优先搜索(BFS). 什么是DFS 图是由节点(Node)和路径(Route)组成的一种数据结构,用于反应各节点间的关系 ...
- 图 深度优先遍历 广度优先遍历 非递归遍历 图解算法过程
图的邻接矩阵表示 通常图的表示有两种方法:邻接矩阵,邻接表. 本文用邻接矩阵实现,一是代码量更少,二是代码风格也更贴近C语言.但不论是图的哪种实现方式,其基本的实现思想是不变的. 1:节点的信息,我们 ...
- (王道408考研数据结构)第六章图-第三节:图的遍历(DFS和BFS)
文章目录 一:图的深度优先遍历(DFS) (1)回溯算法和DFS A:回溯算法的本质 B:回溯算法的框架 C:全排列 (2)图的DFS A:DFS思想 B:动画演示 C:代码 二:图的广度优先遍历(B ...
最新文章
- mysql8.0取消授权_mysql8创建用户、删除用户、授权、取消授权
- Linux下 WiFi rtl 移植,IMX6Q Linux WIFI+BT(RTL8723au)模块移植问题
- 我的人工智能机器人的游戏
- go mod tidy 下载依赖包问题
- Java前沿分享:value或许成为java的新关键字
- bean的scope
- 百度爬虫爬到虚拟链接 网站被黑_网站地图sitemap对SEO优化有什么作用?
- 【技术综述】万字长文详解Faster RCNN源代码
- 涉密服务器虚拟化软件,虚拟化软件解决方案
- 如何评价一个开源项目——协作影响力
- python自动发邮件附件_python自动发送带附件的邮件(163邮箱,亲测可用)
- 1199元起!搭载120W神仙秒充 Redmi Note 11 系列发布
- 《那些年啊,那些事——一个程序员的奋斗史》——30
- Flink算子(Filter、KeyBy、Reduce和Aggregate)
- Effective C++ 精要(第五部分:实现)
- java io中file类_java中IO常见的IO流和file类理论总结
- php微信接口调用,PHP调用微信接口报错
- select系统调用
- 基于junit4的关于个人所得税计算的等价类与边界值_微服务的未来——从单体服务角度看微服务与云计算DevOps结合的演进...
- linux drwxr-xr-x 是什么意思