更改提升图中的边缘目标

Change edge target in boost graph

假设我有一个包含三个顶点的简单图形,我如何将输出边 0 更改为 2 而不是 1

注意:我不想在创建图表时这样做。

假设您遗漏的简单图表:

auto simple_graph() {
    boost::adjacency_list<> g;
    add_edge(0, 1, g);
    add_edge(1, 2, g);
    return g;
}

现在,您可以做的最简单的 for this graph model

// change (0,1) to (0,2):
remove_edge(0, 1, g);
add_edge(0, 2, g);

演示

Live On Compiler Explorer

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>

auto simple_graph() {
    boost::adjacency_list<> g;
    add_edge(0, 1, g);
    add_edge(1, 2, g);
    return g;
}

int main() {
    auto g = simple_graph();
    write_graphviz(std::cout, g);

    // change (0,1) to (0,2):
    remove_edge(0, 1, g);
    add_edge(0, 2, g);

    write_graphviz(std::cout, g);
}

版画

digraph G {
0;
1;
2;
0->1 ;
1->2 ;
}
digraph G {
0;
1;
2;
0->2 ;
1->2 ;
}

所以确实 变成了

其他图表类型

如果您有其他图形类型,其他方法就很自然了:

Live: edge list

#include <boost/graph/edge_list.hpp>
#include <boost/graph/graphviz.hpp>

int main() {
    std::vector edges{std::pair{0, 1}, {1, 2}};
    boost::edge_list g(edges.begin(), edges.end());

    // change (0,1) to (0,2):
    edges[0].second = 2;
}

更新:奖金保留属性

我会写一个 5 行辅助函数:

template <typename V, typename G>
void update_edge_target(V source, V target, V new_target, G& g) {
    if (auto [e, exists] = edge(source, target, g); exists) {
        auto prop = std::move(g[e]);
        remove_edge(e, g);
        add_edge(source, new_target, prop, g);
    }
}

Note: I don't think BGL supports move semantics, so splitting the last line could improve efficiency:

    e = add_edge(source, new_target, g);
    g[e] = std::move(prop);

看到了Live On Compiler Explorer

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>

struct EdgeProps {
    std::map<int, std::string> lots;
    std::string more;
};

auto simple_graph() {
    using namespace boost;
    adjacency_list<vecS, vecS, directedS, no_property, EdgeProps> g;
    add_edge(0, 1,
            {{
                {1, "one"},
                {2, "two"},
                {3, "three"},
            },
            "very heavy data!"},
            g);
    add_edge(1, 2,
            {{
                {4, "four"},
                {5, "five"},
                {6, "size"},
            },
            "needs preserving"},
            g);
    return g;
}

template <typename V, typename G>
void update_edge_target(V source, V target, V new_target, G& g) {
    if (auto [e, exists] = edge(source, target, g); exists) {
        auto prop = std::move(g[e]);
        remove_edge(e, g);
        add_edge(source, new_target, prop, g);
    }
}

// for debug output
#include <fmt/ranges.h>
template <typename G> struct writer : boost::default_writer {
    G const& g;
    explicit writer(G const& g) : g(g) {}

    void operator()(std::ostream& os, auto const& desc) const { handle(os, g[desc]); }

private:
    void handle(std::ostream& os, boost::no_property) const { os << "[]"; }
    void handle(std::ostream& os, EdgeProps const& ep) const {
        os << "[label=" << boost::escape_dot_string(ep.more)
        << ",extra=" << boost::escape_dot_string(fmt::format("{}", ep.lots))
        << "]";
    }
};

int main() {
    auto g = simple_graph();

    writer w{g};
    write_graphviz(std::cout, g, w, w);

    // change (0,1) to (0,2):
    update_edge_target(0, 1, 2, g);

    write_graphviz(std::cout, g, w, w);
}

版画

digraph G {
0[];
1[];
2[];
0->1 [label="very heavy data!",extra="{1: \"one\", 2: \"two\", 3: \"three\"}"];
1->2 [label="needs preserving",extra="{4: \"four\", 5: \"five\", 6: \"size\"}"];
}
digraph G {
0[];
1[];
2[];
0->2 [label="very heavy data!",extra="{1: \"one\", 2: \"two\", 3: \"three\"}"];
1->2 [label="needs preserving",extra="{4: \"four\", 5: \"five\", 6: \"size\"}"];
}

呈现: