我一直在寻找将DAG转换为树的C#示例。
有没有人有正确方向的例子或指示?
澄清更新
我有一个图表,其中包含我的应用程序需要加载的模块列表。每个模块都有一个依赖的模块列表。例如,这里是我的模块,A,B C,D和E.
我想要解决依赖关系并生成一个看起来像这样的树...
- 甲
- + - 乙
- - - - + - Visual C
--------- + - d
- + - 电子
拓扑排序
感谢您提供的信息,如果我执行拓扑排序并反转输出,我将按以下顺序
我想维护层次结构,以便将我的模块加载到正确的上下文中,例如......模块E应该与B在同一个容器中
由于
罗汉
答案 0 :(得分:20)
图表理论答案和程序员对此的回答。我假设你可以自己处理程序员。对于图表的理论答案:
正如其他人所指出的,对你的问题的Graph理论答案是,DAG不能转换为树,而每棵树都是DAG。
然而,(高级程序员回答)如果你想要树用于图形表示,你只对特定模块的依赖性感兴趣,而不是依赖于该模块的依赖性。让我举个例子:
A depends on B and C
B depends on D and E
C depends on D and F
我无法将其显示为ASCII艺术树,原因很简单,因为它无法转换为树。 但是,如果要显示A所依赖的内容,可以显示:
A
+--B
| +--D
| +--E
+--C
+--D
+--F
如您所见,您的树中会有双重条目 - 在这种情况下“仅”D,但如果您在Gentoo树上执行“全部展开”,我保证您的树将至少有1000倍的金额节点,因为有模块。 (至少有100个依赖于Qt的软件包,因此Qt所依赖的所有内容都将在树中至少出现100次。)
如果你有一个“大”或“复杂”的树,最好不要提前动态扩展树,否则你可能会有一个内存密集的过程。
上面这棵树的缺点是,如果你点击打开B,然后是D,你会看到A和B依赖于D,但不是C也依赖于D.但是,根据你的情况,这可能不是重要的是 - 如果你维护一个已加载模块的列表,在加载C时你会看到你已经加载了D,并且没有为C加载它没关系,但对于B.它被加载,就是这样事项。如果你动态维护直接依赖于某个模块的东西,你也可以处理相反的问题(卸载)。
然而,你不能用树做的是你的最后一句话:保留拓扑顺序,即如果B加载到与C相同的容器中,你永远不会在同一个容器中加载C好。或者你可能不得不把所有东西放在一个容器里(不是我完全理解你在“加载到同一个容器中”的意思)
祝你好运!答案 1 :(得分:4)
DAG和树在数学上不是一回事。因此,任何转换都会引入歧义。根据定义,树没有周期,周期。
答案 2 :(得分:2)
为了找到加载模块的订单,您要查找的是DAG的Topological sort。如果边缘从一个模块转移到它依赖的模块(我认为最有可能),你将不得不按照拓扑排序的相反顺序加载模块,因为模块将出现 - 所有模块之前取决于它。
如果你代表DAG使得边缘从依赖于模块的模块转移到依赖于它们的模块(你可以通过反转上图中的所有边缘来实现这一点),你可以按顺序加载模块拓扑类型。
答案 3 :(得分:1)
这在很大程度上取决于您如何代表您的DAG。例如,它可以是一个邻接矩阵(如果从节点i到节点j的边缘为A [i,j] = 1,则为0),或者作为指针系统,或者作为节点数组和数组边缘....
此外,目前尚不清楚您尝试应用哪种转换。连接的DAG 是树,所以我担心你需要澄清一下你的问题。
答案 4 :(得分:0)
如果所有子树都有一个根节点,则只能这样做。
答案 5 :(得分:0)
答案是您想获得一个spanning tree。这甚至是为无向图定义的,因此,即使您有循环,也可以忽略边的方向,获取无向图并获得后者的生成树。您需要哪种生成树取决于您,因为存在很多可能性,例如最小生成树。
我正在寻找的是一种算法,该算法可获取保留所有边缘但保留“副本”节点的“冗余”生成树。不幸的是,我还没有找到这个名字的名字,但是我认为如果您自上而下并且没有丢失的周期,该算法很简单。寻找现成的快速实现。
一般情况是要有一个跨树的森林。