dag的构造 c语言,C#实现有向无环图(DAG)拓扑排序

本文探讨了如何使用拓扑排序算法解决有向无环图中的模块依赖问题,以大学课程和VS项目编译为例,详细解释了ABP模块的加载顺序,并给出了C#代码实现深度优先搜索。通过实例展示了如何利用拓扑排序确保模块间的正确加载顺序,避免循环引用。
摘要由CSDN通过智能技术生成

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

线性结构概念

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

集合中必存在唯一“第一个元素”;

集合中必存在唯一“最后一个元素”;

除了最后一个元素,所有元素均有唯一“后继结点”;

除了第一个元素,所有元素均有唯一“前趋结点”

和我们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中的第一个模块和最后一个模块是确定的。 呢么中间的是怎么排序的呢。其实用的是拓扑算法

e4f813d6787f22bcdeeac4d678c33cfa.png

从图中可以得知:

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

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

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

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

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

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

排序如下:

4e84299a7020dbaf6a3c13d0711259bd.gif

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

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

C#实现深度优先搜索

有这样一个DAG图

e8790d88c084986251139adc02e1080b.png

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

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

4e30b5b68986ecd5eed64538784b7fa9.png

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 MySort(IEnumerable source, Func> getDepends)

{

// 访问过的路径

Dictionary visited = new Dictionary();

// 已经排过序的

List sorted = new List();

foreach (var item in source)

{

Visit(item, getDepends, visited, sorted);

}

return sorted;

}

static void Visit(T item, Func> getDepends, Dictionary visited, List 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);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值