如何将有向无环图(DAG)转换为树

时间:2009-03-09 02:02:19

标签: c# data-structures tree directed-acyclic-graphs

我一直在寻找将DAG转换为树的C#示例。

有没有人有正确方向的例子或指示?

澄清更新

我有一个图表,其中包含我的应用程序需要加载的模块列表。每个模块都有一个依赖的模块列表。例如,这里是我的模块,A,B C,D和E.

  • A没有依赖
  • B取决于A,C和E
  • C取决于A
  • D取决于A
  • E取决于C和A

我想要解决依赖关系并生成一个看起来像这样的树...

- 甲

- + - 乙

- - - - + - Visual C

--------- + - d

- + - 电子

拓扑排序

感谢您提供的信息,如果我执行拓扑排序并反转输出,我将按以下顺序

  • A
  • C
  • d
  • 电子

我想维护层次结构,以便将我的模块加载到正确的上下文中,例如......模块E应该与B在同一个容器中

由于

罗汉

6 个答案:

答案 0 :(得分:20)

图表理论答案和程序员对此的回答。我假设你可以自己处理程序员。对于图表的理论答案:

  • DAG是一组模块,它永远不会发生A需要B,同时,B(或其中一个模块B需要)需要A,在模块中说:没有循环依赖。我已经看到循环依赖发生了(搜索Gentoo论坛的例子),所以你甚至不能100%确定你有DAG,但我们假设你有。检查循环依赖关系并不是很难,所以我建议你在模块加载器的某个地方进行检查。
  • 在树中,永远不会发生的事情是A取决于B和C,B和C都依赖于D(钻石),但这可能发生在DAG中。
  • 此外,树只有一个根节点,但DAG可以有多个“根”节点(即没有任何依赖的模块)。例如像GIMP这样的程序,GIMP程序将是模块集的根节点,但是对于GENTOO,几乎任何具有GUI的程序都是“根”节点,而库等是它们的依赖性。 (I.E. Konqueror和Kmail都依赖于Qtlib,但没有任何东西取决于Konqueror,也没有任何东西取决于Kmail)

正如其他人所指出的,对你的问题的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。这甚至是为无向图定义的,因此,即使您有循环,也可以忽略边的方向,获取无向图并获得后者的生成树。您需要哪种生成树取决于您,因为存在很多可能性,例如最小生成树

我正在寻找的是一种算法,该算法可获取保留所有边缘但保留“副本”节点的“冗余”生成树。不幸的是,我还没有找到这个名字的名字,但是我认为如果您自上而下并且没有丢失的周期,该算法很简单。寻找现成的快速实现。

一般情况是要有一个跨树的森林。