Boost无向图合并顶点 我使用Boost C++库来构建一个邻接表来表示一个无向图。图上的每条边都与各自的权重相关联,我想检查权重是否大于某个阈值,而不是将两个顶点合并在一起

Boost无向图合并顶点 我使用Boost C++库来构建一个邻接表来表示一个无向图。图上的每条边都与各自的权重相关联,我想检查权重是否大于某个阈值,而不是将两个顶点合并在一起,c++,algorithm,boost,graph,boost-graph,C++,Algorithm,Boost,Graph,Boost Graph,如何合并: 对于要合并的顶点,聚集该顶点之间的所有边,并将这些边定向到新顶点 清除合并顶点 删除顶点 我的问题是: 我使用一个简单的程序首先构造算法,然后再使用它。在这个程序中,我使用简单的家谱方法来执行上述步骤。当我使用函数remove_vertexvertex删除顶点时,我得到一个分割错误 我不知道一旦移除顶点,图形是否会自动更新其结构? 我的C++代码如下: #include <boost/graph/adjacency_list.hpp> #include <boost

如何合并:

对于要合并的顶点,聚集该顶点之间的所有边,并将这些边定向到新顶点 清除合并顶点 删除顶点 我的问题是: 我使用一个简单的程序首先构造算法,然后再使用它。在这个程序中,我使用简单的家谱方法来执行上述步骤。当我使用函数remove_vertexvertex删除顶点时,我得到一个分割错误

我不知道一旦移除顶点,图形是否会自动更新其结构? <>我的C++代码如下:

#include <boost/graph/adjacency_list.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/config.hpp>
#include <iostream>
#include <vector>
#include <string>

using namespace std;

typedef boost::property<boost::vertex_index_t, int> vertex_property;
typedef boost::property<boost::edge_weight_t, float> edge_property;
typedef typename boost::adjacency_list <boost::vecS,
                                    boost::vecS,
                                    boost::undirectedS,
                                    vertex_property,
                                    edge_property> Graph;
void boostSampleGraph() {

enum family {
  Jeanie, Debbie, Rick, John, Amanda, Margaret, Benjamin, N };
const char *name[] = { "Jeanie", "Debbie", "Rick", "John", "Amanda",
                       "Margaret", "Benjamin", "N"
 };

 /* actual graph structure  */
 Graph graph;

 /* add vertices to the graph  */
 add_vertex(Jeanie, graph);
 add_vertex(Debbie, graph);
 add_vertex(Rick, graph);
 add_vertex(John, graph);
 add_vertex(Amanda, graph);
 add_vertex(Margaret, graph);
 add_vertex(Benjamin, graph);
 // add_vertex(N, graph);

 /* add edges to the vertices in the graph*/
 add_edge(Jeanie, Debbie, edge_property(0.5f), graph);
 add_edge(Jeanie, Rick, edge_property(0.2f), graph);
 add_edge(Jeanie, John, edge_property(0.1f), graph);
 add_edge(Debbie, Amanda, edge_property(0.3f), graph);
 add_edge(Rick, Margaret, edge_property(0.4f), graph);
 add_edge(John, Benjamin, edge_property(0.6f), graph);
 // add_edge(Benjamin, Benjamin, edge_property(0.7f), graph);

 /* vertex iterator */
 boost::graph_traits<Graph>::vertex_iterator i, end;
 typedef typename boost::graph_traits<
    Graph>::adjacency_iterator AdjacencyIterator;
 /* gets the graph vertex index */
 typedef typename boost::property_map
    <Graph, boost::vertex_index_t >::type IndexMap;
 IndexMap index_map = get(boost::vertex_index, graph);
 /* container to hold the edge descriptor info */
 typedef typename boost::graph_traits<
    Graph>::edge_descriptor EdgeDescriptor;
 EdgeDescriptor e_descriptor;
 typedef typename boost::property_map<Graph, boost::edge_weight_t
                                      >::type EdgePropertyAccess;
 EdgePropertyAccess edge_weights = get(boost::edge_weight, graph);
 typedef typename boost::property_traits<boost::property_map<
    Graph, boost::edge_weight_t>::const_type>::value_type EdgeValue;

 float edge_size = num_vertices(graph);
 std::cout << "# of Edges: " << edge_size  << std::endl;

 /* iterator throught the graph  */
 for (tie(i, end) = vertices(graph); i != end; ++i) {
    std::cout << name[get(index_map, *i)];
    AdjacencyIterator ai, a_end;
    tie(ai, a_end) = adjacent_vertices(*i, graph);

    if (ai == a_end) {
       std::cout << " has no children";
    } else {
       std::cout << " is the parent of ";
    }
    for (; ai != a_end; ++ai) {
       AdjacencyIterator tmp;
       bool found;
       tie(e_descriptor, found) = edge(*i, *ai, graph);
       float weights_ = 0.0f;
       if (found) {
          EdgeValue edge_val = boost::get(
             boost::edge_weight, graph, e_descriptor);
          weights_ = edge_val;

          if (weights_ > 0.3f) {
             // - remove and merge
             AdjacencyIterator aI, aEnd;
             tie(aI, aEnd) = adjacent_vertices(*ai, graph);
             for (; aI != aEnd; aI++) {
                EdgeDescriptor ed;
                bool located;
                tie(ed, located) = edge(*aI, *ai, graph);
                if (located && *aI != *i) {
                   add_edge(
                      get(index_map, *i), get(index_map, *aI), graph);
                }
                std::cout << "\n DEBUG: " << *i  << "  "
                          << *ai  << "  "
                          << *aI << " ";
             }
              std::cout << std::endl;
             clear_vertex(*ai, graph);
             remove_vertex(*ai, graph);
             //  std::cout << "\nGraph Size: " <<
             //  num_vertices(graph) << std::endl;
          }
       }
       // ai = tmp;
       std::cout << name[get(index_map, *ai)];
       if (boost::next(ai) != a_end) {
          std::cout << ", ";
       }
    }
    std::cout << std::endl << std::endl;
 }
 std::cout << "\nGraph Size: " << num_vertices(graph) << std::endl;
} 

int main(int argc, const char *argv[]) {
   boostSampleGraph();

   return 0;
}

我可以得到一些帮助和想法来说明我哪里弄错了。

我不知道你用OP中所示的算法到底想要实现什么

然而,这里有一个可以大大简化代码,至少可以安全地工作:

对顶点id、名称使用顶点绑定属性类型 在可能的情况下使用ranged for循环参见mir,从std::一对迭代器创建boost::iterator_范围的缩写 代码是以独立于容器选择的方式编写的,因此在图形类型声明中用列表替换VEC时,它的工作原理是一样的 它使用out_边而不是相邻的_顶点,以从邻接图概念中获得更多好处,并避免按源、目标顶点反向查找边描述符 最重要的是,它使用一组已删除的顶点。实际的删除将在稍后进行,因此在迭代一个不断变化的容器时,不会出现未定义的行为

在山谷中干净利落地奔跑

之前的图表:

之后的图表:


我不知道你到底想用OP中的算法实现什么

然而,这里有一个可以大大简化代码,至少可以安全地工作:

对顶点id、名称使用顶点绑定属性类型 在可能的情况下使用ranged for循环参见mir,从std::一对迭代器创建boost::iterator_范围的缩写 代码是以独立于容器选择的方式编写的,因此在图形类型声明中用列表替换VEC时,它的工作原理是一样的 它使用out_边而不是相邻的_顶点,以从邻接图概念中获得更多好处,并避免按源、目标顶点反向查找边描述符 最重要的是,它使用一组已删除的顶点。实际的删除将在稍后进行,因此在迭代一个不断变化的容器时,不会出现未定义的行为

在山谷中干净利落地奔跑

之前的图表:

之后的图表:


迭代时删除顶点会导致灾难。您可能希望将它们标记为删除,并在以后删除它们。使用列表进行稳定的搜索iterators@sehe实际上,我想建立一个用于图像分割的区域合并的图形模型。我无法找到任何库,提供了C++中区域合并的功能。如果您知道任何此类性质的库,请提供详细信息。您对区域合并有更好的描述吗?脑海中浮现出了无需击球的助推几何。可能OpenCV也有类似的功能,但我对OpenCV的区域合并知之甚少,我的意思是我有通过超级像素获得的图像块片段。下一步是获取每个片段,然后我想使用一些相似性函数与相邻片段进行比较,如果这两个区域高于某个阈值,则合并这两个区域。我正在使用OpenCV,但我不知道是否有这样的合并方法。在迭代过程中删除顶点会导致灾难。您可能希望将它们标记为删除,并在以后删除它们。使用列表进行稳定的搜索iterators@sehe实际上,我想建立一个用于图像分割的区域合并的图形模型。我无法找到任何库,提供了C++中区域合并的功能。如果您知道任何此类性质的库,请提供详细信息。您对区域合并有更好的描述吗?脑海中浮现出了无需击球的助推几何。可能OpenCV也有类似的功能,但我对OpenCV的区域合并知之甚少,我的意思是我有通过超级像素获得的图像块片段。下一步是获取每个片段,然后我想使用一些相似性函数与相邻片段进行比较,如果这两个区域高于某个阈值,则合并这两个区域。我正在使用OpenCV,但我不知道是否有这样的合并方法。请注意,添加边用于重定向边的行,您没有将权重分配给重新定向的边,这就是为什么在代码中处理后Amanda得到0.0的原因。请检查这是否正确,并请更新您的代码。谢谢你?!你的代码复制了重量吗?我会等。。。预处理
是的。这是你的算法。我只是让它更结实。你的问题是当我使用函数remove_vertexvertex,Graph删除顶点时,我遇到了一个分割错误。。不是关于算法。我很高兴把这件事留给你:我很抱歉没有理解。您的代码运行良好,没有问题。我只是想告诉你我错过了增加重量的部分。所以也许将来如果有人读到这篇文章,他们就能找到正确的解决方案。我应该在我的问题中编辑它。我认为没有足够的信息来判断什么是正确的解决方案。我的回答是,对于未定义的行为,以及在您的案例中的崩溃,正确的解决方案。没有别的了。我认为你在评论中提到的区域合并是一个不同的问题。不要编辑这个问题,你需要一个更好的规范/示例,让人们来帮助你。只需发布一个新问题,并附上一个标记为“是”的好示例,您对区域合并的看法是正确的。然而,我对图论编码还不熟悉,所以我使用上面的原型来学习并构建相应区域合并的图形模型。谢谢你的帮助。。干杯请注意,添加边用于重定向边的那一行,您没有将权重分配给重定向边,这就是为什么在代码中处理后Amanda的权重为0.0。请检查这是否正确,并请更新您的代码。谢谢你?!你的代码复制了重量吗?我会等。。。精确地这是你的算法。我只是让它更结实。你的问题是当我使用函数remove_vertexvertex,Graph删除顶点时,我遇到了一个分割错误。。不是关于算法。我很高兴把这件事留给你:我很抱歉没有理解。您的代码运行良好,没有问题。我只是想告诉你我错过了增加重量的部分。所以也许将来如果有人读到这篇文章,他们就能找到正确的解决方案。我应该在我的问题中编辑它。我认为没有足够的信息来判断什么是正确的解决方案。我的回答是,对于未定义的行为,以及在您的案例中的崩溃,正确的解决方案。没有别的了。我认为你在评论中提到的区域合并是一个不同的问题。不要编辑这个问题,你需要一个更好的规范/示例,让人们来帮助你。只需发布一个新问题,并附上一个标记为“是”的好示例,您对区域合并的看法是正确的。然而,我对图论编码还不熟悉,所以我使用上面的原型来学习并构建相应区域合并的图形模型。谢谢你的帮助。。干杯
#include <boost/graph/adjacency_list.hpp>
#include <iostream>

struct Vertex {
    int id;
    const char* name;

    Vertex(int i = -1, const char* name = "default") : id(i), name(name) {}
};

template <typename It> boost::iterator_range<It> mir(std::pair<It, It> const& p) {
    return boost::make_iterator_range(p.first, p.second);
}
template <typename It> boost::iterator_range<It> mir(It b, It e) {
    return boost::make_iterator_range(b, e);
}

typedef typename boost::adjacency_list<
        boost::vecS, boost::vecS,
        boost::undirectedS,
        Vertex,                                      // bundled properties (id, name)
        boost::property<boost::edge_weight_t, float> // interior property
    > Graph;

Graph make() {
    Graph graph;

    auto Jeanie   = add_vertex(Vertex { 0, "Jeanie" },   graph);
    auto Debbie   = add_vertex(Vertex { 1, "Debbie" },   graph);
    auto Rick     = add_vertex(Vertex { 2, "Rick" },     graph);
    auto John     = add_vertex(Vertex { 3, "John" },     graph);
    auto Amanda   = add_vertex(Vertex { 4, "Amanda" },   graph);
    auto Margaret = add_vertex(Vertex { 5, "Margaret" }, graph);
    auto Benjamin = add_vertex(Vertex { 6, "Benjamin" }, graph);

    add_edge(Jeanie, Debbie,   0.5f, graph);
    add_edge(Jeanie, Rick,     0.2f, graph);
    add_edge(Jeanie, John,     0.1f, graph);
    add_edge(Debbie, Amanda,   0.3f, graph);
    add_edge(Rick,   Margaret, 0.4f, graph);
    add_edge(John,   Benjamin, 0.6f, graph);

    return graph;
}

Graph reduce(Graph graph) {

    /* vertex iterator */
    using vertex_descriptor = boost::graph_traits<Graph>::vertex_descriptor;

    std::cout << "# of vertices: " << num_vertices(graph) << "\n";
    std::cout << "# of edges:    " << num_edges(graph)    << "\n";

    std::set<vertex_descriptor> to_remove;

    /* iterator throught the graph  */
    for (auto self : mir(vertices(graph)))
    {
        std::cout << graph[self].name << (boost::empty(mir(out_edges(self, graph)))? " has no children " : " is the parent of ");

        for(auto edge : mir(out_edges(self, graph))) {
            auto weight    = boost::get(boost::edge_weight, graph, edge);
            auto mid_point = target(edge, graph);

            if (to_remove.count(mid_point)) // already elided
                break;

            if (weight > 0.3f) {
                std::set<vertex_descriptor> traversed;
                for (auto hop : mir(out_edges(mid_point, graph))) {
                    auto hop_target = target(hop, graph);

                    if (hop_target != self)
                        add_edge(self, hop_target, graph);
                    std::cout << "\n DEBUG: " << graph[self].name << "  " << graph[mid_point].name << "  " << graph[hop_target].name << " ";
                }
                std::cout << "\n";

                clear_vertex(mid_point, graph);
                to_remove.insert(mid_point);
            }

            std::cout << graph[mid_point].name;
        }

        std::cout << "\n\n";
    }

    for(auto vd : to_remove)
    {
        clear_vertex(vd, graph);
        remove_vertex(vd, graph);
    }

    std::cout << "# of vertices: " << num_vertices(graph) << "\n";
    std::cout << "# of edges:    " << num_edges(graph)    << "\n";

    return graph;
}

void save(Graph const& g, const char* fname);

int main() {
    auto const g = make();

    auto const h = reduce(g);

    save(g, "before.dot");
    save(h, "after.dot");
}

#include <boost/graph/graphviz.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/property_map/function_property_map.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/format.hpp>
#include <fstream>

void save(Graph const& g, const char* fname) {
    std::ofstream ofs(fname);
    using namespace boost;

    write_graphviz(
            ofs,
            g,
            make_label_writer(make_function_property_map<Graph::vertex_descriptor, std::string>([&] (Graph::vertex_descriptor v){ return g[v].name; })),
            make_label_writer(make_transform_value_property_map([](float v){return boost::format("%1.1f") % v;}, boost::get(edge_weight, g)))
        );
}
# of vertices: 7
# of edges:    6
Jeanie is the parent of 
 DEBUG: Jeanie  Debbie  Jeanie 
 DEBUG: Jeanie  Debbie  Amanda 
DebbieJohnAmanda

Debbie has no children 

Rick is the parent of Jeanie
 DEBUG: Rick  Margaret  Rick 
Margaret

John is the parent of Jeanie
 DEBUG: John  Benjamin  John 
Benjamin

Amanda is the parent of Jeanie

Margaret has no children 

Benjamin has no children 

# of vertices: 4
# of edges:    3