簡體   English   中英

Boost Graph:在子圖上再次運行 DFS

[英]Boost Graph: Running DFS again on a subgraph

我正在使用 boost::directed_graph 並在其上運行 DFS 以確定特定節點的依賴關系。 我將我感興趣的節點的名稱傳遞給訪問者實現。 我的問題是,在 DFS 期間,例如,如果我枚舉圖的左子樹,然后在右子樹中遇到返回左子樹的交叉邊,DFS 將不會重新枚舉這些節點,因為它已經訪問過他們。 我想以交叉邊緣指向的節點為根再次運行 DFS。 例子:

在此處輸入圖像描述

我要為其查找依賴項的節點是 C(枚舉為第 4 個)。 我想取回 A 和 B 作為依賴項,所以在我看來,當我得到這樣的交叉邊緣時,我應該在以 A 為根的子圖上運行 DFS 以獲取這些節點。

typedef boost::directed_graph<Plugin> graph;
typedef graph::edge_descriptor graph_e_des;
typedef std::vector<std::wstring> DependencyVector;

class DependencyVisitor : public boost::default_dfs_visitor
{
public:

    DependencyVisitor(DependencyVector& dependencies, std::wstring& name) :
        m_dependencies(dependencies),
        m_name(name)
    {
    }

    void forward_or_cross_edge(graph_e_des e, const graph& g)
    {
        DependencyVector dependencies;
        std::wstring name = g[e.m_target].name;
        DependencyVisitor v(dependencies, name);

        boost::depth_first_search(g[e.m_target], boost::visitor(v));

        m_dependencies.insert(std::end(m_dependencies), std::begin(dependencies), std::begin(dependencies));
    }

private:
    DependencyVector& m_dependencies;
    std::wstring m_name;
};

我嘗試使用 forward_or_cross_edge 提供的內容再次調用 boost::depth_first_search 但我不知道如何在所需節點處獲取新圖。 我正在閱讀有關 boost::filtered_graph 或 boost::subgraph 的信息,但不清楚這些是正確的解決方案。

提前致謝。

  1. 首先,

    我嘗試使用 forward_or_cross_edge 提供的內容再次調用 boost::depth_first_search 但我不知道如何在所需節點處獲取新圖。

     boost::depth_first_search(g[e.m_target], boost::visitor(v));

    看起來是個錯誤。 g[vd]導致頂點包Plugin&在你的情況下)。 您需要一個頂點描述符,因此您可能的意思是:

     depth_first_search(e.m_target, boost::visitor(v));

    盡管m_target應該提示您正在使用未記錄的實現細節。 更喜歡概念界面:

     depth_first_search(target(e, g), boost::visitor(v));
  2. 其次,這里肯定有一個錯字:

     m_dependencies.insert(end(m_dependencies), begin(dependencies), begin(dependencies));

    你很可能是說

    m_dependencies.insert(end(m_dependencies), begin(dependencies), end(dependencies));
  3. 關於問題的實質,在我看來,您“只是”想要獲得所有傳遞依賴。 你如何最好地實現這一點在很大程度上取決於你的輸入,比如它是否包含循環或構成一棵樹或一片森林。

    在最簡單的情況下,您只需要一個topological_sort

    拓撲排序算法創建頂點的線性排序,這樣如果邊 (u,v) 出現在圖中,則 v 在排序中位於 u 之前。 該圖必須是有向無環圖 (DAG)。 該實現主要包括對depth_first_search()的調用。

    當然,這只給你“凈”排序。

  4. 有更簡單的方法可以組成一個訪問者來動態記錄前輩。 為了獲得靈感,這里有一個簡短的示例,展示了如何記錄前輩:

     #include <boost/graph/depth_first_search.hpp> #include <boost/graph/directed_graph.hpp> #include <boost/graph/graph_utility.hpp> #include <boost/bimap.hpp> #include <iostream> using Name = std::string; // std::wstring? struct Plugin{ Name name; }; using G = boost::directed_graph<Plugin>; using V = G::vertex_descriptor; using E = G::edge_descriptor; using Deps = std::vector<Name>; int main() { G g; auto v1 = add_vertex(Plugin{"Root"}, g); auto v2 = add_vertex(Plugin{"A"}, g); auto v3 = add_vertex(Plugin{"B"}, g); auto v4 = add_vertex(Plugin{"C"}, g); add_edge(v1, v2, g); add_edge(v1, v4, g); add_edge(v2, v3, g); add_edge(v4, v2, g); print_graph(g, get(&Plugin::name, g)); std::vector<V> pred(num_vertices(g)); auto vidx = get(boost::vertex_index, g); auto name = get(&Plugin::name, g); auto pmap = make_iterator_property_map(pred.begin(), vidx); depth_first_search( // g, boost::visitor(make_dfs_visitor( record_predecessors(pmap, boost::on_forward_or_cross_edge{})))); for (V cur = v2, p; (p = pred.at(vidx[cur])).= g;null_vertex(): cur = p) { std:;cout << "predecessor of " << name[cur] << " is " << name[p] << "\n"; } }

    印刷

    Root --> A C A --> BB --> C --> A predecessor of A is C
  5. 拓撲排序假設一個 DAG。 那里的前驅映射假設每個頂點只有 1 個前驅(因此是多根樹/森林)。

    如果您真的想要所有依賴項,可以說圖形本身是最好的來源。 一個簡單的助手是all_dependencies

    住在科利魯

    #include <boost/graph/depth_first_search.hpp> #include <boost/graph/directed_graph.hpp> #include <boost/graph/graph_utility.hpp> #include <fmt/ranges.h> #include <ranges> #include <iostream> using boost::make_iterator_range; using std::views::transform; using Name = std::string; // std::wstring? struct Plugin{ Name name; }; using G = boost::directed_graph<Plugin>; using V = G::vertex_descriptor; using E = G::edge_descriptor; using Deps = std::vector<Name>; template <typename OutputIterator> static OutputIterator all_dependencies(G const& g, V v, OutputIterator out) { for (auto e: make_iterator_range(out_edges(v, g))) { auto dep = target(e, g); *out++ = dep; out = all_dependencies(g, dep, out); } return out; } int main() { G g; auto v1 = add_vertex(Plugin{"Root"}, g); auto v2 = add_vertex(Plugin{"A"}, g); auto v3 = add_vertex(Plugin{"B"}, g); auto v4 = add_vertex(Plugin{"C"}, g); add_edge(v1, v2, g); add_edge(v1, v4, g); add_edge(v2, v3, g); add_edge(v4, v2, g); auto name = get(&Plugin::name, g); print_graph(g, name); std::vector<V> deps; all_dependencies(g, v4, back_inserter(deps)); fmt::print("Deps of {} are {}\n", // name[v4], // deps | transform([name](V v) { return name[v]; })); }

    印刷

    Root --> A C A --> BB --> C --> A Deps of C are ["A", "B"]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM