对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序.

线性结构概念

总的来说,“线性结构”是一个有序数据元素的集合 线性结构满足以下特点:

  1. 集合中必存在唯一“第一个元素”;
  2. 集合中必存在唯一“最后一个元素”;
  3. 除了最后一个元素,所有元素均有唯一“后继结点”;
  4. 除了第一个元素,所有元素均有唯一“前趋结点”

和我们abp Module很像,第一个加载模块永远是其ABP核心模块,最后一个模块永远是我们的启动模块

举例

1.大学课程排序

大学课程的学习是有先后顺序的,C语言是基础,数据结构依赖于C语言,其它课程也有类似依赖关系。这样的一个课程安排是怎么实现的呢?

2.VS项目编译顺序

假设VS中有三个项目A,B,C,它们的关系如下。VS编译器是如何判断三个项目的编译顺序的呢?

A->B->C A引用B B引用C

A->B->C->A 提示循环引用

ABP的Module

ABP中的模块也是如此,不可循环引用相互依赖A->B B->A X

前面说到ABP中的第一个模块和最后一个模块是确定的。

呢么中间的是怎么排序的呢。其实用的是拓扑算法



从图中可以得知:

1.A模块是最核心的,不依赖于其他任何模块

2.D依赖E和B,E依赖B和C,B依赖C和A,C依赖A

那么根据拓扑排序,应该如何排序呢?

1.从图中找一个没有前驱指向它的顶点

2.删除该顶点.以及该顶点的前驱

3.重复步骤 1 and 2 ,直到图中顶点为空 或者 找不到步骤1中这样的顶点 为止.

排序如下:



结果就是D->E->B->C->A 排完之后正好对应D依赖E和B,E依赖B和C,B依赖C和A,C依赖A

这个顺序在ABP的模块这看来是行不通的,需要在反转一次,最先加载A,才行。

C#实现深度优先搜索

有这样一个DAG图



如果对它进行排序的话,其实过程是这样的.

图中,顶点A是没有指向它的前驱的,所以从它开始访问



1.访问 A

2.访问 B

3.访问 C

在访问了 B 后应该是访问 B 的另外一个顶点,这里可以是随机的也可以是有序的,具体取决于你存储的序列顺序,这里先访问 C 。

4.访问 E

5.访问 D

这里访问 D 是因为 B 已经被访问过了,所以访问顶点 D 。

6.访问 F

因为顶点 C 已经被访问过,所以应该回溯访问顶点 B 的另一个有向边指向的顶点 F 。

7.访问 G

那么代码应该如何写呢?

source:需要排序的集合

getDepends:一个func委托,用于获取当前模块依赖的其他模块

方法内部维护了一个字典对象Visited 用于存储已经访问过的模块,key表示模块,value是一个bool,true时表示正在处理,false表示以及处理完成,

处理完成的模块会加入到sorted集合中

static List<T> MySort<T>(IEnumerable<T> source, Func<T, IEnumerable<T>> getDepends)
{
// 访问过的路径
Dictionary<T, bool> visited = new Dictionary<T, bool>();
// 已经排过序的
List<T> sorted = new List<T>();
foreach (var item in source)
{
Visit<T>(item, getDepends, visited, sorted);
}
return sorted;
} static void Visit<T>(T item, Func<T, IEnumerable<T>> getDepends, Dictionary<T, bool> visited, List<T> sorted)
{
//已经访问过了
if (visited.ContainsKey(item))
{
bool isVisit = visited[item];
if (isVisit == true)
{
throw new Exception("循环引用");
}
}
//未访问
else
{
visited.Add(item, true);//true :正在访问 false:访问完成 //获取所有依赖
var depends = getDepends(item);
foreach (var depend in depends)
{
Visit(depend, getDepends, visited, sorted);
} //访问完成
visited[item] = false;
sorted.Add(item);
} }

完整demo github

C#实现有向无环图(DAG)拓扑排序的更多相关文章

  1. 算法87-----DAG有向无环图的拓扑排序

    一.题目:课程排表---210 课程表上有一些课,是必须有修学分的先后顺序的,必须要求在上完某些课的情况下才能上下一门.问是否有方案修完所有的课程?如果有的话请返回其中一个符合要求的路径,否则返回[] ...

  2. CSU 1804: 有向无环图(拓扑排序)

    http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1804 题意:…… 思路:对于某条路径,在遍历到某个点的时候,之前遍历过的点都可以到达它,因此在 ...

  3. 大数据工作流任务调度--有向无环图(DAG)之拓扑排序

    点击上方蓝字关注DolphinScheduler(海豚调度) |作者:代立冬 |编辑:闫利帅 回顾基础知识: 图的遍历 图的遍历是指从图中的某一个顶点出发,按照某种搜索方法沿着图中的边对图中的所有顶点 ...

  4. [笔记] 有向无环图 DAG

    最小链覆盖 (最长反链) 最小链覆盖 \(=n-\) 最大匹配. 考虑首先每个点自成一条链,此时恰好有 \(n\) 条链,最终答案一定是合并(首尾相接)若干条链形成的. 将两点匹配的含义其实就是将链合 ...

  5. 【模板整合计划】图论—有向无环图 (DAG) 与树

    [模板整合计划]图论-有向无环图 (DAG) 与树 一:[拓扑排序] 最大食物链计数 \(\text{[P4017]}\) #include<cstring> #include<cs ...

  6. 判断有向无环图(DAG)

    1.拓扑排序 bfs 所有入度为0的先入选. 2.tarjan 1个点1个集合 3.暴力 一个点不能重新到达自己

  7. pagerank算法在数学模型中的运用(有向无环图中节点排序)

    一.模型介绍 pagerank算法主要是根据网页中被链接数用来给网页进行重要性排名. 1.1模型解释 模型核心: a. 如果多个网页指向某个网页A,则网页A的排名较高. b. 如果排名高A的网页指向某 ...

  8. 题目1448:Legal or Not(有向无环图判断——拓扑排序问题)

    题目链接:http://ac.jobdu.com/problem.php?pid=1448 详解链接:https://github.com/zpfbuaa/JobduInCPlusPlus 参考代码: ...

  9. 图->有向无环图->拓扑排序

    文字描述 关于有向无环图的基础定义: 一个无环的有向图称为有向无环图,简称DAG图(directed acycline graph).DAG图是一类较有向树更一般的特殊有向图. 举个例子说明有向无环图 ...

随机推荐

  1. BZOJ3672/UOJ7 [Noi2014]购票

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  2. review11

    public byte[] getBytes()方法使用平台默认的字符编码,将当前字符串转换为一个字节数组.如 byte d[] = "Java你好".getBytes(); 如果 ...

  3. python基础5 - 产生随机数

    随机数 在 Python 中,要使用随机数,首先需要导入 随机数 的 模块 —— “工具包” import random 导入模块后,可以直接在 模块名称 后面敲一个 . 然后按 Tab 键,会提示该 ...

  4. PhpSpreadsheet如何读取excel文件

    PhpSpreadsheet如何读取excel文件 一.总结 一句话总结:万能的百度,直接搜代码就好,绝对有,毕竟github上面4000+的关注,说明很多人用了这个,使用照着demo倒是异常简单 二 ...

  5. thinkphp中composer方式安装的插件如何使用

    thinkphp中composer方式安装的插件如何使用 一.总结 一句话总结:任何东西都是可以百度或者google搜到的,要自己先想怎么解决,解决不出来迅速百度,不要自己臆断 1.在tp5框架的什么 ...

  6. Linux命令之awk_1

    简介 awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大.简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再 ...

  7. The import javax.servlet.jsp.JspWriter cannot be resolved' error

    Add servlet-api.jar and jsp-api.jar from Tomcat 6.0 library to ecipse project.

  8. python直接赋值,浅拷贝和深拷贝

    本文参考自<Python 直接赋值.浅拷贝和深度拷贝解析> 定义 直接赋值:就是对象的引用(别名) 浅拷贝(copy):拷贝父对象,不拷贝对象内部的子对象 深拷贝(deepcopy):co ...

  9. 51nod 1672 贪心/队列

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1672 1672 区间交 基准时间限制:1 秒 空间限制:131072 K ...

  10. ng-file-upload - samples

    <script src="angular.min.js"></script> <!-- shim is needed to support non-H ...