我有一个 DAG。我有这个操作来在两个节点之间添加一条边。
如果 A 可以从 B 到达,则 B 是 A 的父级。如果 A 可以从 B 到达而无需经过另一个节点,则 B 是 A 的直接父节点。
此图的要求是:
- 没有循环。
- 对于任何节点,都有一个直接父节点列表 P[1],P[2],P[3]...对于任何 i 和 j,P[i] 都不是 P[j] 的父节点。
如果添加一条边,则不满足要求 1,则不构造该边。如果添加一条边,则不满足要求 2,则构建边,但将修改直接父项,以满足要求 2。
例如有3个节点
- A、直系父母:无
- B、直系父母:A
- C、直系父母:A
现在,如果我在 B 和 C 之间添加一条边,我们有
- C、直系父母:A、B
但是 A 是 B 的父级,不满足要求 2,因此 A 从 C 的直接父级中删除,我们有
- C、直系父母:B
目前这是我所做的:将边缘从 A 添加到 B(这个 A 成为 B 的父级)
- 通过 BFS 检查 B 是否是 A 的父级。如果是这样,不要添加边缘。(这确保没有循环)
- 通过 BFS 检查 A 是否已经是 B 的父级。如果是这样,请不要添加边缘。
- 找到 A 的父级与 B 的直接父级的交集。这是通过通过 BFS 找到 A 的每个父级来完成的。从 B 的直接父级中删除交集,并将 A 添加为 B 的直接父级。(2 和 3 确保满足要求 2)
这很慢。它在 5k 节点级别发生故障(我正在寻找它来处理任何少于 100k 节点的图),速度变得不可接受,添加节点边缘需要 0.02 秒。
我有一种感觉,第 1 步和第 2 步可以用其他算法一步完成。
我曾想过使用拓扑排序,但它必须横穿整个图,这对于我的第 1 步和第 2 步来说是最坏的情况。添加新节点时,排序将被打乱。所以我每次插入都必须运行拓扑排序,所以它不会产生任何好处。对于第 3 步,必须找到 A 的整个父母集。这个过程相当缓慢,因为平均而言它横穿了图表的相当一部分。
我怎样才能使它更有效率?