【问题标题】:How to detect cycles in directed graph in iterative DFS?如何在迭代 DFS 中检测有向图中的循环?
【发布时间】:2017-05-17 12:07:40
【问题描述】:

我当前的项目具有一组带有输入和输出的节点。每个节点都可以获取其输入值并生成一些输出值。这些输出可以用作其他节点的输入。为了最小化所需的计算量,在应用程序启动时检查节点依赖关系。更新节点时,它们会以相互依赖的相反顺序更新。

也就是说,节点类似于有向图。我正在使用迭代 DFS(不使用递归来避免大图中的堆栈溢出)来计算依赖关系并创建更新节点的顺序。

我还想避免图中的循环,因为循环依赖会破坏更新器算法并导致永远运行的循环。

有通过跟踪递归堆栈上的节点来使用 DFS 查找循环的递归方法,但是有没有办法迭代地完成它?然后我可以将循环搜索嵌入到主依赖解析器中以加快速度。

【问题讨论】:

    标签: recursion depth-first-search directed-graph


    【解决方案1】:

    网上有很多可用的循环检测算法。最简单的是 Dijkstra 算法的增强版本。您维护访问节点的列表和到达那里的成本。在您的设计中,将“成本”替换为 路径

    在算法的每次迭代中,您都会抓取“活动”列表中的下一个节点,并查看图中跟随它的每个节点(即它的每个依赖项)。如果该节点在“已访问”列表中,则您有一个循环。您在到达此处时维护的path 显示了循环路径。

    这足以让你感动吗?

    【讨论】:

      【解决方案2】:

      试试时间戳。在您的节点上添加元时间戳并将其设置为零。

      上一个答案(不适用):

      当您开始搜索时,增加或获取 time() 标记。那么,当 您访问一个节点,将其与当前搜索时间戳进行比较。如果它 是一样的,那么你就找到了一个循环。如果没有,则设置印章 到当前。

      下一次搜索,再次递增。

      好的,这就是我假设您执行 DFS 搜索的方式:

      • 将根节点添加到堆栈(用于搜索)和向量(用于更新)。
      • 弹出堆栈并将当前节点的子节点添加到堆栈和向量中
      • 循环直到堆栈为空
      • 反向迭代向量并更新值(通过引用子节点)

      问题:循环会导致同一组节点被添加到堆栈中。

      解决方案 1:在添加到 DFS 搜索堆栈之前,使用布尔值/时间戳来查看节点是否已被访问。这将消除循环,但不会解决它们。你可以吐出一个错误然后退出。

      解决方案 2:使用时间戳,但每次弹出堆栈时都会增加它。如果一个子节点设置了时间戳,并且小于当前时间戳,则您找到了一个循环。这是踢球者。向后迭代值时,您可以检查子节点的时间戳以查看它们是否大于当前节点。如果小于,那么您已经找到了一个循环,但您可以使用默认值。

      事实上,我认为解决方案 1 可以通过在更新值并在启动时将所有节点设置为默认值时从不跟随多个子节点来解决。解决方案 2 会在评估图形时给您一个警告,而解决方案 1 只会在创建向量时给您一个警告。

      【讨论】:

      • 这种方法也可以称之为圆:A 是起始节点。 A 依赖于 B 和 C。B 和 C 都依赖于 D。或者我错过了什么?我理解您的方法可以替代“已访问”标志。
      • 好点。我假设您正在排队您的依赖节点并通过弹出队列的前端(DFS)来处理它们。但是,您似乎还想反向更新它们。需要更新答案...
      • 我想更新它们,这样如果 A 依赖于 B,B 就会更新然后 A。所以基本上把它们放在一个堆栈上(是的,可以称之为“反向队列”)。该堆栈被保存,然后馈送到更新程序线程。在树遍历期间我不运行更新。一个循环是这样的:A 是起始节点。 A依赖B。B依赖C。C依赖A。这种依赖不可能解决,所以我需要识别这种情况。
      猜你喜欢
      • 2018-03-12
      • 1970-01-01
      • 1970-01-01
      • 2016-03-28
      • 1970-01-01
      • 2017-01-19
      • 1970-01-01
      • 1970-01-01
      • 2016-01-30
      相关资源
      最近更新 更多