Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 在有向无环图中,有没有一种有效的方法来确定一个叶节点是否可以从另一个任意节点到达?_Algorithm_Optimization_Graph_Directed Acyclic Graphs - Fatal编程技术网

Algorithm 在有向无环图中,有没有一种有效的方法来确定一个叶节点是否可以从另一个任意节点到达?

Algorithm 在有向无环图中,有没有一种有效的方法来确定一个叶节点是否可以从另一个任意节点到达?,algorithm,optimization,graph,directed-acyclic-graphs,Algorithm,Optimization,Graph,Directed Acyclic Graphs,不确定叶节点是否仍然是合适的术语,因为它不是真正的树(每个节点可以有多个子节点,也可以有多个父节点),而且我实际上正在尝试查找所有的根节点(这实际上只是一个语义问题,如果你颠倒所有边的方向,它们将是叶节点) 现在我们只是遍历整个图(可以从指定的节点访问),但这会有点昂贵,所以我想知道是否有更好的算法来实现这一点。我想的一件事是,我们跟踪已经访问过的节点(在穿越不同路径时),而不重新检查这些节点 还有其他算法优化吗 我们还考虑过保留一个根节点列表,该节点是其后代,但是如果我们需要检查它是否在每次添

不确定叶节点是否仍然是合适的术语,因为它不是真正的树(每个节点可以有多个子节点,也可以有多个父节点),而且我实际上正在尝试查找所有的根节点(这实际上只是一个语义问题,如果你颠倒所有边的方向,它们将是叶节点)

现在我们只是遍历整个图(可以从指定的节点访问),但这会有点昂贵,所以我想知道是否有更好的算法来实现这一点。我想的一件事是,我们跟踪已经访问过的节点(在穿越不同路径时),而不重新检查这些节点

还有其他算法优化吗

我们还考虑过保留一个根节点列表,该节点是其后代,但是如果我们需要检查它是否在每次添加、移动或删除节点时都会更改,那么维护这样的列表似乎也会相当昂贵

编辑:

这不仅仅是查找单个节点,而是查找作为端点的所有节点

此外,没有节点的主列表。每个节点都有其子节点和父节点的列表。(当然,这并不完全正确,但提前从数据库中提取数百万个节点的成本太高,可能会导致OutOfMemory异常)

编辑2:

可能会改变也可能不会改变可能的解决方案,但图的底部很重,因为最多有几十个根节点(我正在尝试查找)和数百万个(可能数千万或数亿)叶节点(我的起点)。

只需对访问的节点进行着色(跟踪)

Python中的示例:

def reachable(nodes, edges, start, end):
  color = {}
  for n in nodes:
    color[n] = False
  q = [start]
  while q:
    n = q.pop()
    if color[n]:
      continue
    color[n] = True
    for adj in edges[n]:
      q.append(adj)
  return color[end]

根据您的结构,有几种方法的速度可能更快,但通常您需要的是遍历

深度优先搜索会遍历每个可能的路径,跟踪已访问的节点。这是一个递归函数,因为在每个节点上,您必须分支并尝试它的每个子节点。如果你不知道用哪种方法寻找对象,没有比这更快的方法,你只需要尝试每种方法!你肯定需要跟踪你已经去过的地方,否则会浪费时间。它应该要求按节点数的顺序进行完全遍历

广度优先搜索与此类似,但在“继续”之前访问节点的每个子节点,从而建立与所选根的距离层。如果预期目标位置靠近根节点,则速度会更快。如果期望它沿着一条路径一路走下去,那么速度会慢一些,因为它迫使您遍历每一条可能的边

也许保留一个已知根节点的列表是对的,但折衷的办法是,无论何时更改图形,基本上都必须进行搜索。如果您很少更改图形,这是可以接受的,但是如果您更改图形的频率高于生成此信息所需的频率,那么当然成本太高

编辑:信息更新。 听起来我们实际上在寻找两个任意节点之间的路径,根/叶语义一直在切换。DepthFirstSearch(DFS)从一个节点开始,然后针对每个未访问的子节点递归。如果找到目标节点,则中断。由于递归的计算方式,它将沿着“左”路径遍历所有节点,然后在到达“右”路径之前枚举此距离处的节点。如果目标节点可能是右侧的第一个子节点,则这将耗费大量时间且效率低下。“面包头”步进式行走,覆盖所有儿童,然后再往前走。因为您的图形像树一样底部沉重,所以两者的执行时间大致相同

当图形为底部重时,您可能会对反向遍历感兴趣。从目标节点开始向上走,因为该方向上的节点相对较少。只要节点通常有更多的父节点而不是子节点,这个方向就会快得多。你也可以把这些方法结合起来,上下一步,然后比较节点列表,在中间相遇。(如果忽略每个步骤所做工作的两倍,这种组合可能看起来最快)

但是,由于您说过您的图形存储为子对象列表,因此您没有向后遍历图形的真正方法。节点不知道其父节点是什么。这是一个问题。要修复它,你必须让一个节点知道它的父节点是什么,方法是在graph update上添加数据,或者创建整个结构的副本(你说的太大了)。它将需要重写整个结构,这听起来可能是不可能的,因为此时它是一个大型数据库。 有很多工作要做。
对于要计算位数组f(x)的顶点x,每个位对应于根顶点Ri,1(resp 0)表示“x可以(resp不能)从根顶点Ri到达”


您可以将图形划分为一个“上限”“设置包含所有目标根R的U,如果x在U中,则x的所有父节点都在U中。例如,距离+1处的所有顶点集,因为在给定信息的情况下,这是可行的,但这些节点是我们的业务对象,我们需要在处理完这些节点后,将其全部着色。我已经提到了跟踪已经访问的节点,尽管包含颜色数据的结构不需要是这些业务对象的一部分。为每个算法保留额外的数据会很麻烦(而且不是线程安全的)。将这些对象简单地映射到布尔值(如上面示例中的dict)就足够了。另一件事是,正如我在编辑中提到的(不确定您是否看到它),我没有所有节点的列表