C++ Boost.Graph如何合并两个顶点/收缩边

C++ Boost.Graph如何合并两个顶点/收缩边,c++,boost,graph,boost-graph,C++,Boost,Graph,Boost Graph,如何在Boost.Graph处合并两个顶点/收缩边 我需要将边从顶点A移动到顶点B,并删除顶点A-是否有任何内置函数?或者邻接列表中有什么特别的东西 如果没有这样的功能,为什么?我认为这是常见的图形操作 编辑:我知道可以手动进行编辑,但也有一些角点情况(如保留边属性),这就是为什么它很适合放在库中的原因 我最感兴趣的是知道Boost.Graph是否已经有了那个操作(可能有一些别致的名字?)。如果没有-为什么这样的原始操作/算法不在图形库中。也许我遗漏了什么,而且这个操作不是原始的或者很少使用 我

如何在Boost.Graph处合并两个顶点/收缩边

我需要将边从顶点A移动到顶点B,并删除顶点A-是否有任何内置函数?或者邻接列表中有什么特别的东西

如果没有这样的功能,为什么?我认为这是常见的图形操作

编辑:我知道可以手动进行编辑,但也有一些角点情况(如保留边属性),这就是为什么它很适合放在库中的原因

我最感兴趣的是知道Boost.Graph是否已经有了那个操作(可能有一些别致的名字?)。如果没有-为什么这样的原始操作/算法不在图形库中。也许我遗漏了什么,而且这个操作不是原始的或者很少使用

我不需要半生不熟的概念快速证明

半生不熟的概念快速证明 您可以使用
add_edge()
remove_vertex()
对根据
邻接列表定义的图形进行操作

#include <iostream>
#include <iterator>
#include <boost/graph/adjacency_list.hpp>

using V = unsigned;
using E = std::pair<V, V>;
using G = boost::adjacency_list<boost::vecS, boost::vecS>;

void print_graph(G const& g)
{
    auto vs = boost::vertices(g);
    for (auto vit = vs.first; vit != vs.second; ++vit) {
        auto neighbors = boost::adjacent_vertices(*vit, g);
        for (auto nit = neighbors.first; nit != neighbors.second; ++nit)
            std::cout << "{" << *vit << "," << *nit << "}" << ", ";
    }
    std::cout << "\n";
}

void contract_vertices(V b, V a, G& g)
{
    auto be = boost::adjacent_vertices(b, g);
    for (auto beit = be.first; beit != be.second; ++beit)
        add_edge(a, *beit, g);
    remove_vertex(b, g);
}

int main()
{
    // named vertices
    auto const A = V { 1 };
    auto const B = V { 2 };

    // construct the graph
    auto e = std::vector<E> { { A, 3 }, { B, 4 } };
    auto g = G { std::begin(e), std::end(e), 4 };

    print_graph(g);
    contract_vertices(B, A, g);    
    print_graph(g);
}
#包括
#包括
#包括
使用V=无符号;
使用E=std::pair;
使用G=boost::邻接列表;
无效打印图(G常量和G)
{
自动vs=boost::顶点(g);
用于(自动vit=vs.first;vit!=vs.second;++vit){
自动相邻=boost::相邻的_顶点(*vit,g);
for(自动nit=neights.first;nit!=neights.second;++nit)

std::cout手动执行时,应手动删除每个
b
边,而不是顶点:

void collapse_vertices(V b, V a, G& g)
{
    auto be = boost::adjacent_vertices(b, g);
    for (auto beit = be.first; beit != be.second; ++beit)
    {
        add_edge(a, *beit, g);
        remove_edge(b, *beit, g);
    }
}
给出你想要的
{1,3},{1,4},


我不知道为什么它没有包括在(我的知识中)在BGL中,但该函数就是它的作用。

库中没有通用函数,因为通用函数不可能知道在“角点情况”中需要做什么。如果顶点X与顶点a和B都有边,该怎么办?该函数应该删除X-a,还是删除X-B并将X-a移动到X--B?如果从X到A的边(正在删除的顶点)具有必须保留或修改的属性?只有应用程序代码知道在删除或移动边时如何处理属性


“委托”这些决定,正如qble建议的那样,没有任何意义。如果将关于如何处理已删除边的属性的决定“委托”给应用程序代码,那么应用程序代码将必须查找并循环必须删除的边。因此,它必须重复与泛型函数相同的工作。它需要ht还可以自己删除边,一旦完成了每个删除边的属性,就不用麻烦调用泛型函数。

downvoter,问题出在哪里了?问题可能出在大喊“我不需要半生不熟的概念快速证明”。(我知道,你并没有那么坏的意思,甚至只是说你获得了赏金。)1.我认为塌陷顶点应该有检入循环来避免循环-比如如果(a!=*beit)添加边(a,*beit,g);
。2.我知道手动操作是可能的-我更感兴趣的是为什么Boost.Graph没有内置的功能?(或者它有?用一些不明显的名字?)3.它不仅是关于将移除顶点的边添加到另一个顶点,而且还关于保留边数据(Boost.Graph有“属性”)-显然,这需要更多的手动代码+还有其他一些特殊情况,这就是为什么它很适合在库中。是的,您应该在生产代码中完成所有这三件事。在任何情况下,Boost.Graph提供了编写
折叠\u顶点的所有原语
“从理论上讲,在通用算法中使用合适的模板参数应该可以做到这一点。”-是的,准确地说-将责任委托给用户。良好的基于库的合同顶点将迫使用户考虑角落案例(通过强制参数)否则很容易被忽略。接受答案,因为它是最详细的一个,谢谢!@qble很高兴能提供帮助!如果您要添加到的边已经存在怎么办?如果您要删除的边具有属性怎么办?@ravenpoint它以最自然的方式按预期运行:如果您添加已经存在的边,它将被添加,并且您始终可以检查和删除重复项;这是手动完成的,因此传递属性由您负责。确实存在必须在通用函数中处理的角落案例。但这并不意味着它可以完成。当角落案例有选择时,决策应该通过参数委托给用户。
Boost.Graph
already将许多决策委托给用户(如带有邻接列表的自定义容器),这就是它是泛型的原因。“然后应用程序代码必须找到必须删除的边并在边上循环”-不,它不必这样做。如果有疑问,泛型版本可以只使用作为参数传递的用户函子。