【问题标题】:Using Boost Graph to search through a DAG Graph?使用 Boost Graph 搜索 DAG Graph?
【发布时间】:2009-10-07 15:58:55
【问题描述】:

我需要搜索 DAG 图,但我不想在看到所有其他节点都指向它的有向链接之前越过一个节点。

是否存在处理这种特殊情况的现有算法,深度优先搜索和呼吸优先搜索不适用于这种遍历顺序。

即:

A -> B
B -> C
C -> D
A -> C

我不想在看到 B 和 C 之前到达 D。

【问题讨论】:

  • 不要将您的 DAG 图带到 ATM 机上并使用您的 PIN 码,否则您可能会感染 HIV 病毒。

标签: c++ boost graph boost-graph


【解决方案1】:

您正在寻找的是 Kahn (1962) 的拓扑排序算法。这不是目前在 BGL 中实现的拓扑排序算法,它是基于 DFS 的,访问所有顶点,并以相反的拓扑顺序输出结果,而是与 BFS 非常相似,并且完全按照您在您的描述中描述的方式访问顶点第一段。您必须自己编写遍历,但算法很简单。

查看拓扑排序维基百科条目中列出的第一个算法:http://en.wikipedia.org/wiki/Topological_sorting。另请参阅 Sedgewick 的“C 语言算法”中的程序 19.8。

提示 1:使用辅助数据结构来维护每个顶点的 in 边数,实际上不要执行“从图中删除边”部分。

提示 2:对于一个有效的 GPLV3 示例,您可以在我的 CoFlo 控制流图生成和分析项目中查看 Kahn 算法的实现,特别是此处的文件 topological_visit_kahn.h:http://coflo.svn.sourceforge.net/viewvc/coflo/trunk/src/controlflowgraph/topological_visit_kahn.h?view=log

【讨论】:

    【解决方案2】:

    所以我最近的想法是在添加或删除边时对整个图进行拓扑排序,并存储每个节点要遍历的直接子节点的顺序(这可能是一个有点棘手的算法编写)。

    然后我做一个修改的广度优先搜索(如chaos所建议的那样),并在下面的bfs伪代码中,修改该行:

    for each vertex v in Adj[u]
    

    成为:

    for each vertex v in OrderedAdj[u]
    

    伪代码:

    BFS(G, s)
      for each vertex u in V[G]
        color[u] := WHITE 
        d[u] := infinity 
        p[u] := u 
      end for
      color[s] := GRAY 
      d[s] := 0 
      ENQUEUE(Q, s)
      while (Q != Ø) 
        u := DEQUEUE(Q)
        for each vertex v in Adj[u]
          if (color[v] = WHITE)
            color[v] := GRAY 
            d[v] := d[u] + 1  
            p[v] := u  
            ENQUEUE(Q, v)
          else
            if (color[v] = GRAY) 
              ...
            else 
              ...
        end for
        color[u] := BLACK
      end while
      return (d, p)
    

    我相信这是实现这一目标的最佳方式,但确实需要我编写自己的 bfs 遍历算法,以及在每个节点上存储节点的顺序(我希望避免的内存开销),并编写我的自己的 dfs 访问者用于查找订单并将其存储在缓存阶段的节点上。

    我很惊讶没有现成的方法来做到这一点,因为在我看来这是一种相当常见的导航 dag 图的方法......

    【讨论】:

      【解决方案3】:

      您无法使用普通的图遍历算法来做到这一点,因为您需要该算法神奇地了解图结构,而这些知识是在不违反自身要求的情况下无法遍历的。您必须使用两遍方法,首先构建反向树,告诉您哪些节点与其他节点有连接,然后进行修改后的广度优先搜索,该搜索使用来自第一遍的信息来适当地延迟遍历。而且我怀疑某些图结构可能会导致第二遍死锁。

      【讨论】:

        【解决方案4】:

        先进行拓扑排序,然后在排序后的图上进行深度优先搜索怎么样?

        这行得通吗?

        【讨论】:

        • 我认为这必须是对排序图的广度优先搜索。
        【解决方案5】:

        任何 DAG 至少有一个叶子节点。删除任何叶节点节点和所有传入弧会留下另一个 DAG。递归地,这个较小的 DAG 也至少有一个叶节点。通过以这种方式递归删除所有节点,最终根节点成为叶节点。

        如果您现在反转删除节点的顺序,您将获得具有所需属性的遍历顺序。通过最后访问叶节点,您可以保证首先看到所有父节点。

        【讨论】:

        • 谢谢,这也称为拓扑排序,在 Boost 中就像这样实现 :) 现在我将如何从这个有序的节点列表到仅搜索下游的节点任何特定的节点(仍然使用这个顺序),最好不要编写我自己的遍历算法?
        • 您的意思是,当那个特定节点不是根节点时?看起来很简单:对整个 DAG 进行拓扑排序,并丢弃从您的特定节点无法访问的所有节点。其余节点是根于您的特定节点的子图的遍历顺序。
        猜你喜欢
        • 2010-12-02
        • 2011-05-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多