写在前面

如果觉得有所收获,记得点个关注和点个赞,感谢支持。
今天遇到有向无环图的一些问题,感觉挺有意思的,而且这些问题的思路特点都差不多,所以想着记录一下。在图论中,如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。而提到DAG,就差不多会联想到拓扑排序,拓扑排序是指由某个集合上的一个偏序得到该集合上的一个全序的操作。拓扑排序常用来确定一个依赖关系集中,事物发生的顺序。拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从顶点A到顶点B的路径,那么在排序中B出现在A的后面。DAG在区块链中得到很广泛的应用哦。

概念

图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V, E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。图按照边的有无方向性分为无向图和有向图。

图中某个节点与其他节点的直连边条数称为该节点的度。有向图中,指向其他节点的边成为出度,被其他节点指向的边称为入度。如果在有向图中,无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。

偏序,集合内只有部分元素之间在这个关系下是可以比较的, 比如:比如复数集中并不是所有的数都可以比较大小,那么“大小”就是复数集的一个偏序关系。全序,集合内任何一对元素在在这个关系下都是相互可比较的,比如:有限长度的序列按字典序是全序的。最常见的是单词在字典中是全序的。

邻接表与邻接矩阵

邻接表和邻接矩阵是图的两种常用存储表示方式,用于记录图中任意两个顶点之间的连通关系,包括权值。下面我们来实际举例一下,对于图 G=(V, E) 而言,其中 V 表示顶点集合,E 表示边集合。给定了概念之后,对于无向图 graph,图的顶点集合和边集合如下:



对于有向图 digraph,图的顶点集合和边集合如下:


邻接表

无向图 graph 表示

有向图 digraph 表示

若采用邻接表表示,则需要申请 ∣V∣|V|∣V∣ 个列表,每个列表存储一个顶点出发的所有相邻顶点。如果图 GGG 为有向图,则 ∣V∣|V|∣V∣ 个列表存储的总顶点个数为 ∣E∣|E|∣E∣ ;如果图 GGG 为无向图,则 ∣V∣|V|∣V∣ 个列表存储的总顶点个数为 2∣E∣2|E|2∣E∣ (暂不考虑自回路)。因为需要申请大小为 ∣V∣|V|∣V∣ 的数组来保存节点,对节点分配序号,所以需要申请大小为 ∣V∣|V|∣V∣ 的额外存储空间,即邻接表方式的存储空间复杂度为 O(∣V∣+∣E∣)O(|V|+|E|)O(∣V∣+∣E∣) 。

邻接矩阵

无向图 graph 表示

有向图 digraph 表示

若采用邻接矩阵表示,则需要申请空间大小为 ∣V∣2|V|^2∣V∣2 的二维数组,在二位数组中保存每两个顶点之间的连通关系,则无论有向图或无向图,邻接矩阵方式的存储空间复杂度皆为 O(∣V∣2)O(|V|^2)O(∣V∣2) 。若只记录图中顶点是否连通,不记录权值大小,则可以使用一个二进制位来表示二维数组的每个元素,并且根据无向图的特点可知,无向图的邻接矩阵沿对角线对称,所以可以选择记录一半邻接矩阵的形式来节省空间开销。

根据邻接表和邻接矩阵的结构特性可知,当图为稀疏图、顶点较多,即图结构比较大时,更适宜选择邻接表作为存储结构。当图为稠密图、顶点较少时,或者不需要记录图中边的权值时,使用邻接矩阵作为存储结构较为合适。

拓扑排序

拓扑排序:就是一个有向无环图的所有定点的线性序列。如果在图中,有一条从A点到B点的路线,那么在拓扑排序中,点A一定排在点B的前面。这个东西,是比较难理解,再上图说话吧。比如在这个有向无环图中,它用拓扑排序,该怎么进行呢?

  • 先找一个起点,很明显,这个起点就1号点了,因为这个点,没有任何其他指向它的路线。如果存在多个这样的点,那么随意输出就可以了,也就是说,可能存在多个拓扑序列。
  • 然后将这个起点删除,并同时删除这个起点发射出去的路线。
  • 重复上面两个步骤,直到这张有向无环图的所有点都被删除干净。

如果到某个阶段,发现当前图中不存在像1号点这样的起点了,那么这张图就不是有向无环图了。最后,一个完整的拓扑排序就完成了,结果为:1、2、4、3、5。

代码实现

为了更方便理解,我们这里直接贴出一道题,根据这道题的实现代码来体会,这道题是完全按照拓扑排序的思路进行解答的。题目如下

解题思路

  • 本题可约化为: 课程安排图是否是 有向无环图(DAG)。即课程间规定了前置条件,但不能构成任何环路,否则课程前置条件将不成立。
  • 思路是通过 拓扑排序 判断此课程安排图是否是 有向无环图(DAG) 。 拓扑排序原理: 对 DAG 的顶点进行排序,使得对每一条有向边 (u,v)(u, v)(u,v) ,均有 uuu(在排序记录中)比 vvv 先出现。亦可理解为对某点 vvv 而言,只有当 vvv 的所有源点均出现了,vvv 才能出现。

算法流程

  • 统计课程安排图中每个节点的入度,生成 入度表 indegrees
  • 借助一个队列 queue,将所有入度为 0 的节点入队。
  • queue 非空时,依次将队首节点出队,在课程安排图中删除此节点 pre
    • 并不是真正从邻接表中删除此节点 pre,而是将此节点对应所有邻接节点 cur 的入度 −1,即 indegrees[cur] -= 1
    • 当入度 −1后邻接节点 cur 的入度为 0,说明 cur 所有的前驱节点已经被 “删除”,此时将 cur 入队。
  • 在每次 pre 出队时,执行 numCourses--
    • 若整个课程安排图是有向无环图(即可以安排),则所有节点一定都入队并出队过,即完成拓扑排序。换个角度说,若课程安排图中存在环,一定有节点的入度始终不为 0
    • 因此,拓扑排序出队次数等于课程个数,返回 numCourses == 0 判断课程是否可以成功安排。

算法可视化

实现

public boolean canFinish(int numCourses, int[][] prerequisites) {int[] indegrees = new int[numCourses];List<List<Integer>> adjacency = new ArrayList<>();Queue<Integer> queue = new LinkedList<>();for(int i = 0; i < numCourses; i++)adjacency.add(new ArrayList<>());for(int[] cp : prerequisites) {indegrees[cp[0]]++;adjacency.get(cp[1]).add(cp[0]);}for(int i = 0; i < numCourses; i++)if(indegrees[i] == 0) queue.add(i);while(!queue.isEmpty()) {int pre = queue.poll();numCourses--;for(int cur : adjacency.get(pre))if(--indegrees[cur] == 0) queue.add(cur);}return numCourses == 0;
}

带你了解有向无环图和拓扑排序相关推荐

  1. 【图论】有向无环图的拓扑排序

    1. 引言 有向无环图(Directed Acyclic Graph, DAG)是有向图的一种,字面意思的理解就是图中没有环.常常被用来表示事件之间的驱动依赖关系,管理任务之间的调度.拓扑排序是对DA ...

  2. 有向无环图DAG 拓扑排序 代码解释

    目录: DAG定义 举例描述 实际运用 算法描述 算法实战 算法可视化 定义 在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序(英语:Topological ...

  3. 数据结构-考研难点代码突破 (C++实现有向无环图的拓扑排序)

    文章目录 1. AOV网 2. 拓扑排序 C++代码 1. AOV网 AOV网∶若用DAG 图(有向无环图)表示一个工程,其顶点表示活动,用有向边<Vi,Vj>表示活动 Vi必须先于活动V ...

  4. 判定有向无环图 (拓扑排序)

    问题描述: 给出一张有向图,问它是否存在环. 解题思路: 这里可以用到拓扑排序. 拓扑排序的定义 拓扑排序应用于有向无环图之中,排序完以后会出现这样的性质:对于一个点p,只对排序位置在它之后的点有边. ...

  5. C#实现有向无环图(DAG)拓扑排序

    对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在 ...

  6. 有向无环图的拓扑排序

    拓扑排序 对于一个有向无环图,我们可以这样确定一个图中顶点的顺序:  对于所有的u.v,若存在有向路径u-->v,则在最后的顶点排序中u就位于v之前.这样确定的顺序就是一个图的拓扑排序.     ...

  7. 有向无环图的拓扑排序 关键路径

    拓扑排序:在不违背先决条件的基础上将有向无环图排成线性序列 - 排序结果不唯一 - 用一维数组Indegree存储各顶点的入度 - 采用邻接表与队列 bool TopSort(LGraph Graph ...

  8. 有向无环图(DAG)拓扑排序的两种方法

    如下图的DAG: 第一种: (1)从AOV网中选择一个没有前驱的顶点并且输出它: (2)从AOV网中删除该顶点,并且上去所有该顶点为尾的弧: (3)重复上述两步,直到全部顶点都被输出,或者AOV网中不 ...

  9. HDU - 128 确定比赛名次(基于有向无环图(GAD)的排序--拓扑排序)

    题目链接:https://vjudge.net/contest/325616#problem/A 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N,进行比赛,比赛结束 ...

最新文章

  1. 2022-2028年中国PVC糊树脂行业市场深度分析及市场规模预测报告
  2. openssl之EVP系列之1---算法封装
  3. 洛谷 - P4768 [NOI2018]归程(Kruskal重构树+树上倍增+最短路)
  4. Intellij IDEA集成JProfiler性能分析神器
  5. Linux socket多进程服务器框架二
  6. jetty9优化的两处地方
  7. Linux 安装 VMware Player
  8. linux如何查看python的版本_Python基础知识:如何检查 Python 版本
  9. MAC 系统下怎么新建一个桌面
  10. IE浏览器中链接用谷歌浏览器打开或其他程序打开
  11. returned a response status of 405 Method Not Allowed
  12. 【效率翻倍】vscode使用指南
  13. 别找ERP试用版了,直接送你一个免费的
  14. Your ApplicationContext is unlikely tostart due to a @ComponentScan of the defau
  15. 网络安全态势感知和OODA模型
  16. kanzi与第三方app融合,比如地图导航视频、互联娱乐视频
  17. 唯链品牌重塑全球发布会在新加坡成功举办
  18. 使用matlab进行回声处理(三重回声)-数字信号处理课设
  19. 一个超酷的开源uHand2.0机械手掌项目
  20. 【音乐随想】道,流浪者之歌 与神思者

热门文章

  1. 史上最全“大数据”学习资源集合
  2. android studio管理源码下载,基于Android Studio的Android挂号管理系统JAVA后端
  3. Socket函数的参数
  4. CEO的干货分享:张子阳软商创业记录
  5. SQL常用函数、索引、视图、序列
  6. 成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
  7. Java高并发秒杀API(三)之Web层
  8. 谈谈美国大学的常任轨(tenure track)制度
  9. 三星Note3预览图片与浮窗指令使用技巧
  10. 服务器无线桥接,服务器无线桥接设置方法