拓扑排序算法介绍

拓扑排序解决的是一系列相互依赖的事件的排序问题,比如Ant中有很多的Task,而某些Task依赖于另外的Task,编译之前需要清理空间,打包之前要先编译,但其它一些Task处理顺序可以调换(是无所谓前后,不是并行), 如何安排Task的执行顺序就可以用拓扑排序解决。熟悉Java的朋友应该都知道Spring,一个非常优秀的解决组件(Bean)依赖的框架,组件之间可能有依赖关系,也可能没有关系,如何按顺序创建组件也是相同的问题。本文使用的是图搜索算法里面的深度优先排序算法解决问题。需要特别指出的是拓扑排序算法的结果很可能有多个(不依赖的可以调换位置),而算法也可以有多种,深度优先排序算法只是其中一种而已。拓扑排序为线性排序,效率为O(|V|+|E|),其中|V|表示顶点数,|E|表示边的数量。

Java实现有向图的拓补排序:

思路:关于有向图的拓补排序:

首先我们要确定好一个规则,就是一个顶点他的那些入度对应的顶点全部用完,才可以轮到该顶点自己!

如图:

例如v2,他有俩入度,那么要想使用v2,就必须等待v1和v3执行完!

首先我们建立一个栈Stack,把v0,v1,v3压栈;

然后拿出v3,打印v3,看看v3有哪些出度对应的顶点(这里是v2和v13),看看这俩顶点除了v3这个入度外还有没有其他的入度,有的话不能压栈。。

以此类推。。。

代码实现如下:

public class DnGraphTopologic {private int numVertexes;private VertexNode[] adjList;// 邻接顶点的一维数组public DnGraphTopologic(int numVertexes) {this.numVertexes = numVertexes;}private void createGraph() {VertexNode node0 = new VertexNode(0, "v0");VertexNode node1 = new VertexNode(0, "v1");VertexNode node2 = new VertexNode(2, "v2");VertexNode node3 = new VertexNode(0, "v3");VertexNode node4 = new VertexNode(2, "v4");VertexNode node5 = new VertexNode(3, "v5");VertexNode node6 = new VertexNode(1, "v6");VertexNode node7 = new VertexNode(2, "v7");VertexNode node8 = new VertexNode(2, "v8");VertexNode node9 = new VertexNode(1, "v9");VertexNode node10 = new VertexNode(1, "v10");VertexNode node11 = new VertexNode(2, "v11");VertexNode node12 = new VertexNode(1, "v12");VertexNode node13 = new VertexNode(2, "v13");adjList = new VertexNode[numVertexes];adjList[0] = node0;adjList[1] = node1;adjList[2] = node2;adjList[3] = node3;adjList[4] = node4;adjList[5] = node5;adjList[6] = node6;adjList[7] = node7;adjList[8] = node8;adjList[9] = node9;adjList[10] = node10;adjList[11] = node11;adjList[12] = node12;adjList[13] = node13;node0.firstEdge = new EdgeNode(11);node0.firstEdge.next = new EdgeNode(5);node0.firstEdge.next.next = new EdgeNode(4);node1.firstEdge = new EdgeNode(8);node1.firstEdge.next = new EdgeNode(4);node1.firstEdge.next.next = new EdgeNode(2);node2.firstEdge = new EdgeNode(9);node2.firstEdge.next = new EdgeNode(6);node2.firstEdge.next.next = new EdgeNode(5);node3.firstEdge = new EdgeNode(13);node3.firstEdge.next = new EdgeNode(2);node4.firstEdge = new EdgeNode(7);node5.firstEdge = new EdgeNode(12);node5.firstEdge.next = new EdgeNode(8);node6.firstEdge = new EdgeNode(5);node8.firstEdge = new EdgeNode(7);node9.firstEdge = new EdgeNode(11);node9.firstEdge.next = new EdgeNode(10);node10.firstEdge = new EdgeNode(13);node12.firstEdge = new EdgeNode(9);EdgeNode n11 = new EdgeNode(11);EdgeNode n5 = new EdgeNode(5);EdgeNode n4 = new EdgeNode(4);EdgeNode n8 = new EdgeNode(8);EdgeNode n2 = new EdgeNode(2);EdgeNode n9 = new EdgeNode(9);EdgeNode n6 = new EdgeNode(6);EdgeNode n13 = new EdgeNode(13);EdgeNode n7 = new EdgeNode(7);EdgeNode n12 = new EdgeNode(12);EdgeNode n10 = new EdgeNode(10);/** 为啥下面不可以同一个n5多个共用?因为公用的话,会出现上面n5还有next,到了下面n5明明不应该有,但是也还是有了,* 当时我还想,如果不是同一个对象的话,那出度会不会受影响,但是我想多了,因为出度不是由n5决定的,* 而是由adjlist来决定的,这个倒是只创建了一个对象。*/// node0.firstEdge = n11;// node0.firstEdge.next = n5;// node0.firstEdge.next.next = n4;// node1.firstEdge = n8;// node1.firstEdge.next = n4;// node1.firstEdge.next.next = n2;// node2.firstEdge = n9;// node2.firstEdge.next = n6;// node2.firstEdge.next.next = n5;// node3.firstEdge = n13;// node3.firstEdge.next = n2;// node4.firstEdge = n7;// node5.firstEdge = n12;// node5.firstEdge.next = n8;// node6.firstEdge = n5;// node8.firstEdge = n7;// node9.firstEdge = n11;// node9.firstEdge.next = n10;// node10.firstEdge = n13;// node12.firstEdge = n9;}/*** 拓扑排序* * @author Administrator* @throws Exception* */private void topologicalSort() throws Exception {Stack<Integer> stack = new Stack<>();int count = 0;int k = 0;// 开头就先把入度为0的vertexNode压栈(如果没有,就代表有回环)for (int i = 0; i < numVertexes; i++) {if (adjList[i].in == 0) {stack.push(i);}}while (stack.size() > 0) {// 取出栈中的下标值int pop = stack.pop();System.out.println("访问到:" + adjList[pop].data);count++;// 判断该顶点的其他出度对应的顶点是否无入度了,没有的话打印for (EdgeNode node = adjList[pop].firstEdge; node != null; node = node.next) {if (--adjList[node.getAdjVert()].in == 0) {// 证明该顶点没有了入度,可以压栈stack.push(node.getAdjVert());}}}if (count < numVertexes) {throw new Exception("完犊子了,拓扑排序失败");}}// 边表顶点class EdgeNode {private int adjVert;private EdgeNode next;private int weight;public EdgeNode(int adjVert) {this.adjVert = adjVert;}public int getAdjVert() {return adjVert;}public void setAdjVert(int adjVert) {this.adjVert = adjVert;}public EdgeNode getNext() {return next;}public void setNext(EdgeNode next) {this.next = next;}public int getWeight() {return weight;}public void setWeight(int weight) {this.weight = weight;}}// 邻接顶点class VertexNode {private int in;// 入度private String data;private EdgeNode firstEdge;public VertexNode(int in, String data) {this.in = in;this.data = data;}public int getIn() {return in;}public void setIn(int in) {this.in = in;}public String getData() {return data;}public void setData(String data) {this.data = data;}public EdgeNode getFirstEdge() {return firstEdge;}public void setFirstEdge(EdgeNode firstEdge) {this.firstEdge = firstEdge;}}public static void main(String[] args) {DnGraphTopologic dnGraphTopologic = new DnGraphTopologic(14);dnGraphTopologic.createGraph();try {dnGraphTopologic.topologicalSort();} catch (Exception e) {e.printStackTrace();}}
}

  

转载于:https://www.cnblogs.com/Booker808-java/p/8827259.html

有向图的拓补排序算法相关推荐

  1. AcWing 有向图的拓补排序 题解 (拓补排序 模板)

    有向无环图中才存在拓扑序列,拓扑序列就是将有向无环图中的所有点排成一个线性序列 方法:用数组模拟队列,先将所有入度为0的点入队,一次从队列中取出队首,将队首指向下一个节点的边去除,以某个点为队首,一直 ...

  2. 每日一题30:拓补排序

    问题描述 所谓拓补排序就是确定图中节点的一种顺序,使得某些在别的节点访问之前不能访问到的节点排在后面.所以该算法的核心是每一步选择一个没有入度的节点,因为没有入度意味着该节点没有前驱,得到一个节点后, ...

  3. 士兵排队问题(拓补排序)(附简要拓补排序思想及算法)

    题目描述 有N个士兵(1<=N<=100),编号依次为1,2,...,N.队列训练时,指挥官要把士兵从高到矮排成一行,但指挥官只知道"1 比2 高,7 比 5高"这样的 ...

  4. leetcode *210. 课程表 II(拓补排序)(2020.5.17)

    [题目]*210. 课程表 II 现在你总共有 n 门课需要选,记为 0 到 n-1. 在选修某些课程之前需要一些先修课程. 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们 ...

  5. 51nod-生产口罩(拓补排序+DP)by zyz

    题目:生产口罩 链接:http://class.51nod.com/Classes/Problem.html#courseProblemId=1718&classId=129 //注:题目来自 ...

  6. Aov网络与拓补排序的实现

    测试的节点分布如下: 测试代码如下: /** 拓补排序的实现,使用邻接链表存储有向图 */ #include <iostream> #include <cstdio> #inc ...

  7. 【BZOJ3036】绿豆蛙的归宿 拓补排序+概率

    [BZOJ3036]绿豆蛙的归宿 Description 随着新版百度空间的下线,Blog宠物绿豆蛙完成了它的使命,去寻找它新的归宿. 给出一个有向无环的连通图,起点为1终点为N,每条边都有一个长度. ...

  8. 奖金(拓补排序的应用)

    谁应该高谁的入度++,并记录下谁比低的高(低的得出度),所以入度为零的就是最低的(好不公平),找出所有最低的,将他们算作一层,奖金++(算是拓补排序吧) #include<cstdio> ...

  9. HDU4324 - Triangle LOVE 拓补排序

    HDU4324 - Triangle LOVE : http://acm.showproblemhdu.edu.cn/.php?pid=4324 标准的拓补排序,上代码 : #include < ...

  10. 后缀自动机求多个串的最长公共子串+拓补排序讲解+LCS2 - Longest Common Substring II

    网上所有关于后缀自动机拓补排序的文章,都默认读者会拓补排序,简直了. 后缀自动机的拓补排序,就是按照长度进行排序,在进行特定操作的时候,通过较长的后缀来更新较短的后缀.那么也就是通过拓补排序中排名靠后 ...

最新文章

  1. “二子乘舟”的故事很难讲
  2. 用python解算法谜题_编程的乐趣 用Python解算法谜题
  3. uc3842开关电源电路图_UC3842构成的开关电源电路
  4. 用WMI修改计算机名和IP
  5. linux提示密码没有凑效,陈连福的生信博客 | 第16期培训班将于2021.01.23-2021.02.01期间在武汉市举办,提前报名有有优惠!...
  6. MySQL服务的启动与停止-使用图形界面工具
  7. B端产品经理,应从哪些方面理解业务?
  8. OpenShift 4 - 部署Mirror Registry并复制Image
  9. linux mint 19新功能,Linux Mint 19.3将在2019年12月正式发布,附新功能简介
  10. Spring-BeanDefinitionRegistryPostProcessor接口
  11. 那年我整理的JavaEE面试题
  12. 复变函数在计算机科学中的应用,复变函数的应用以及发展史
  13. 梦幻模拟战更新服务器正在维护,“梦幻模拟战2.0”更新维护公告
  14. 21天刷题计划之2.1—禁忌雷炎(Java语言描述)
  15. 群晖安装Calibre(含格式转换豆瓣元数据推送kindle)221211
  16. 鼓励与信任让人变得更强大
  17. XP系统电脑开机桌面上什么文件都没有啦怎么办
  18. python基础知识之整除、取余、幂运算
  19. C#访问网页、保存网页
  20. 《看板实战》读书笔记 XMIND版本

热门文章

  1. 问卷调查设计以及敏感性问题调查
  2. Git—— 1.安装
  3. zscore标准化步骤_数据的标准化
  4. 绘制相同到期日欧式期权组合收益图(python)
  5. Au:突发性噪音降噪方法
  6. lol微信登录服务器,LOL开启微信登录功能测试 绑定微信登陆方法一览
  7. 工作中如何进行接口测试
  8. 微信小程序数据拼接_微信小程序字符串和变量如何拼接
  9. spssfisher判别分析步骤_SPSS判别分析
  10. 锁定计算机怎么设密码忘记了怎么办,如何设置笔记本电脑指纹密码忘了怎么办...