我正在尝试找到有向无环图的宽度......由任意排序的节点列表表示,甚至没有邻接列表。
图形/列表用于并行GNU Make-like工作流管理器,它使用文件作为执行顺序的标准。每个节点都有一个源文件和目标文件列表。我们有一个哈希表,因此,给定一个文件名,可以确定产生它的节点。通过这种方式,我们可以通过检查使用该表生成每个源文件的节点来找出节点的父节点。
这是我目前唯一的能力,而不会严重改变代码。代码已经公开使用了一段时间,我们要做的最后一件事是显着改变结构并且发布不好。不,我们没有时间严格测试(我在学术环境中)。理想情况下,我们希望我们能够做到这一点,而不会做任何比向节点添加字段更危险的事情。
我将发布社区维基答案,概述我目前的方法及其缺陷。如果有人想编辑它,或者用它作为起点,请随意。如果我能做些什么来澄清事情,我可以在必要时回答问题或发布代码。
谢谢!
编辑:对于任何关心的人,这将是在C.是的,我知道我的伪代码是在一些可怕的拙劣Python中看起来很像。我有点希望这种语言不重要。答案 0 :(得分:1)
这就是我(Platinum Azure,原作者)到目前为止所做的一切。
制剂/扩充:
算法:
查找所有节点的直接子节点数;另外,通过添加子节点== 0的节点来确定叶子。
for l in L:
l.children = 0
for l in L:
l.level = 0
for p in l.parents:
++p.children
Leaves = []
for l in L:
l.children_left = l.children
if l.children == 0:
Leaves.append(l)
为每个节点分配“反向深度”级别。通常按深度,我的意思是拓扑排序并将深度= 0分配给没有父项的节点。但是,我想我需要反转这个,深度= 0对应叶子。此外,我们希望确保没有节点被添加到队列中,而没有所有子节点首先“查看它”(以确定其正确的“深度级别”)。
max_level = 0
while !Leaves.empty():
l = Leaves.pop()
for p in l.parents:
--p.children_left
if p.children_left == 0:
/* we only want to append parents with for sure correct level */
Leaves.append(p)
p.level = Max(p.level, l.level + 1)
if p.level > max_level:
max_level = p.level
现在每个节点都有一个级别,只需创建一个数组,然后再次遍历列表以计算每个级别中的节点数。
level_count = new int[max_level+1]
for l in L:
++level_count[l.level]
width = Max(level_count)
这就是我到目前为止的想法。有没有办法改进它?它一直是线性时间,但它有五到六次线性扫描,可能会有很多缓存未命中等。我不得不怀疑是否有一种方法可以利用更好的数据结构来利用某些地方 - 而无需实际更改基础代码以外的节点扩充。
有什么想法吗?
答案 1 :(得分:1)
我认为你在这里考虑的“宽度”并不是你想要的 - 宽度取决于你如何为你有选择的每个节点分配等级。当您决定是将所有源分配到0级还是将所有汇点分配到最大级别时,您会注意到这一点。
相反,您只想计算节点数并除以“关键路径长度”,这是dag中最长的路径。这给出了图的平均并行度。它仅取决于图形本身,它仍然可以指示图形的宽度。
要计算关键路径长度,只需执行您正在执行的操作 - 关键路径长度是您最终分配的最大级别。
答案 2 :(得分:1)
在我看来,当你进行这种类型的最后一分钟开发时,最好将新结构与你已经使用的结构分开。在这一点上,如果我被时间紧迫,我会寻求一个更简单的解决方案。
问题是Keith Randall问的问题,这是您需要的正确测量吗?