我有一个DAG。我有这个操作在两个节点之间添加边。
如果A可以从B到达,则B是A的父亲。如果A可以从B到达而不通过另一个节点,则B是A的直接父节点。
此图表的要求是:
如果添加边缘,则不满足要求1,则不构造边。 如果添加边缘,则不满足要求2,则构造边缘,但直接父节点将以满足要求2的方式进行修改。
例如,有3个节点
现在,如果我在B和C之间添加边,我们有
但A是B的父级,不符合要求2,因此A从C的直接父级中移除,我们有
目前这就是我所做的: 从A到B添加边缘(此A成为B的父级)
这很慢。它在5k节点级别崩溃(我正在寻找这个来处理节点少于100k的任何图形),速度变得不可接受,添加节点边缘为0.02秒。
我感觉步骤1和2可以通过一些其他算法一步完成。
我想过使用拓扑排序,但它必须横向整个图形,这是我的第1步和第2步的最坏情况。添加新节点时,排序将中断。所以每次插入时我都要运行拓扑排序,所以它不会产生任何好处。 对于第3步,必须找到整个A的父母。这个过程相当慢,因为它平均横向图的一个不错的部分。
如何提高效率?
答案 0 :(得分:4)
你的问题归结为“可以在DAG中插入边缘比O(v + e)快吗?”根据要求(1)。要求(2)是一个更局部的约束,不需要检查整个图形。
我认为答案是否定的:在最坏的情况下你不能比O(v+e)
更好(其中v
是节点/顶点的数量,而e
是的数量是{{1}}边缘)。
毫无疑问,有些技巧可以改善预期的性能,具体取决于DAG的属性及其随时间的变化情况。这似乎是一个活跃的研究课题。例如,我想某些图表可能对集群节点有益。在集群中插入边缘只需要在集群子DAG内进行检查。但是,您需要一个适当的群集策略,支持在添加节点时以便宜的方式更新群集等。
答案 1 :(得分:0)
不了解您的建议,但建议您添加索引。 每行索引必须存储对metaparent-metachild
metaparent - 链接中的父级:parent,parent-of-parent,...
metachid - 链接中的孩子:孩子,孩子,...因此对于图A-> B-> C存在以下索引: A-B,B-C,A-C 在B-> C之间添加显式边缘导致断言,因为这样的条目已经存在。因此算法的复杂性从n ^ 2减少到ln(n)