【问题标题】:Modifying vertex properties in a Boost::Graph修改 Boost::Graph 中的顶点属性
【发布时间】:2010-10-14 21:02:29
【问题描述】:

我想弄清楚如何使用 boost::graph 来存储一些信息。但是,我希望将信息绑定到每个顶点。盯着库的文档会发现(a)写得不好的文档,或者(b),我显然不像我想象的那样擅长 C++。选择两个。

我正在寻找一个简单的使用示例。

【问题讨论】:

  • 在 17 年盯着 boost 文档后,我有同样的两个启示。

标签: c++ boost graph properties boost-graph


【解决方案1】:

捆绑的属性易于使用:

using namespace boost;

struct vertex_info { 
    std::string whatever; 
    int othervalue; 
    std::vector<int> some_values; 
};

typedef adjacency_list<vecS, vecS, undirectedS, vertex_info> graph_t;

graph_t g(n);

g[0].whatever = "Vertex 0";

[...]

等等。

另请参阅docs

另一种非常有用的顶点属性是外部属性。您可以声明适当大小的std::vectors 并将它们用作属性。

【讨论】:

  • 这必须是公认的答案。尤其是因为一个竞争性的答案,目前投票最高,是对您展示的这个功能的重新实现,它已经在库中!您的示例代码也是我在网上找到的关于如何设置简单的 boost 图形库使用的最直接的示例。谢谢。
  • +1;抱歉,我迟到了 :) 只是一个旁注:“你可以声明 std::vectors”——只有当你使用 vecS 时才如此,然后只适用于顶点(而不是边)IIRC。
  • 您还可以通过 TMP 的魔力使用多个属性:这里 ->informit.com/articles/article.aspx?p=25756&seqNum=7
【解决方案2】:

我不喜欢 boost::graph 的嵌套模板属性方法,所以我为所有内容编写了一个小包装器,它基本上允许将任何结构/类作为顶点/边缘属性。可以访问访问结构成员的属性。

为了保持灵活性,这些结构被定义为模板参数。

这里是代码:

/* definition of basic boost::graph properties */
enum vertex_properties_t { vertex_properties };
enum edge_properties_t { edge_properties };
namespace boost {
    BOOST_INSTALL_PROPERTY(vertex, properties);
    BOOST_INSTALL_PROPERTY(edge, properties);
}


/* the graph base class template */
template < typename VERTEXPROPERTIES, typename EDGEPROPERTIES >
class Graph
{
public:

    /* an adjacency_list like we need it */
    typedef adjacency_list<
        setS, // disallow parallel edges
        listS, // vertex container
        bidirectionalS, // directed graph
        property<vertex_properties_t, VERTEXPROPERTIES>,
        property<edge_properties_t, EDGEPROPERTIES>
    > GraphContainer;


    /* a bunch of graph-specific typedefs */
    typedef typename graph_traits<GraphContainer>::vertex_descriptor Vertex;
    typedef typename graph_traits<GraphContainer>::edge_descriptor Edge;
    typedef std::pair<Edge, Edge> EdgePair;

    typedef typename graph_traits<GraphContainer>::vertex_iterator vertex_iter;
    typedef typename graph_traits<GraphContainer>::edge_iterator edge_iter;
    typedef typename graph_traits<GraphContainer>::adjacency_iterator adjacency_iter;
    typedef typename graph_traits<GraphContainer>::out_edge_iterator out_edge_iter;

    typedef typename graph_traits<GraphContainer>::degree_size_type degree_t;

    typedef std::pair<adjacency_iter, adjacency_iter> adjacency_vertex_range_t;
    typedef std::pair<out_edge_iter, out_edge_iter> out_edge_range_t;
    typedef std::pair<vertex_iter, vertex_iter> vertex_range_t;
    typedef std::pair<edge_iter, edge_iter> edge_range_t;


    /* constructors etc. */
    Graph()
    {}

    Graph(const Graph& g) :
        graph(g.graph)
    {}

    virtual ~Graph()
    {}


    /* structure modification methods */
    void Clear()
    {
        graph.clear();
    }

    Vertex AddVertex(const VERTEXPROPERTIES& prop)
    {
        Vertex v = add_vertex(graph);
        properties(v) = prop;
        return v;
    }

    void RemoveVertex(const Vertex& v)
    {
        clear_vertex(v, graph);
        remove_vertex(v, graph);
    }

    EdgePair AddEdge(const Vertex& v1, const Vertex& v2, const EDGEPROPERTIES& prop_12, const EDGEPROPERTIES& prop_21)
    {
        /* TODO: maybe one wants to check if this edge could be inserted */
        Edge addedEdge1 = add_edge(v1, v2, graph).first;
        Edge addedEdge2 = add_edge(v2, v1, graph).first;

        properties(addedEdge1) = prop_12;
        properties(addedEdge2) = prop_21;

        return EdgePair(addedEdge1, addedEdge2);
    }


    /* property access */
    VERTEXPROPERTIES& properties(const Vertex& v)
    {
        typename property_map<GraphContainer, vertex_properties_t>::type param = get(vertex_properties, graph);
        return param[v];
    }

    const VERTEXPROPERTIES& properties(const Vertex& v) const
    {
        typename property_map<GraphContainer, vertex_properties_t>::const_type param = get(vertex_properties, graph);
        return param[v];
    }

    EDGEPROPERTIES& properties(const Edge& v)
    {
        typename property_map<GraphContainer, edge_properties_t>::type param = get(edge_properties, graph);
        return param[v];
    }

    const EDGEPROPERTIES& properties(const Edge& v) const
    {
        typename property_map<GraphContainer, edge_properties_t>::const_type param = get(edge_properties, graph);
        return param[v];
    }


    /* selectors and properties */
    const GraphContainer& getGraph() const
    {
        return graph;
    }

    vertex_range_t getVertices() const
    {
        return vertices(graph);
    }

    adjacency_vertex_range_t getAdjacentVertices(const Vertex& v) const
    {
        return adjacent_vertices(v, graph);
    }

    int getVertexCount() const
    {
        return num_vertices(graph);
    }

    int getVertexDegree(const Vertex& v) const
    {
        return out_degree(v, graph);
    }


    /* operators */
    Graph& operator=(const Graph &rhs)
    {
        graph = rhs.graph;
        return *this;
    }

protected:
    GraphContainer graph;
};

使用它,您可以访问如下属性:

struct VertexProperties {
    int i;
};

struct EdgeProperties {
};

typedef Graph<VertexProperties, EdgeProperties> MyGraph;

MyGraph g;

VertexProperties vp;
vp.i = 42;

MyGraph::Vertex v = g.AddVertex(vp);

g.properties(v).i = 23;

当然你可能对你的图表结构有其他需求,但是修改上面的代码应该很容易。

【讨论】:

  • 太棒了!这段代码使 Boost Graph 对我有用。我也不喜欢使用嵌套模板。
  • 只是为了避免像我这样的新手遇到问题。需要在代码开头添加:#include #include #include #include #include #include 使用命名空间boost; (我很抱歉这个可怕的评论)
  • 惊人的解决方案!它拯救了我的一天 =) 我只是卡在迭代器上......我找不到访问图表根节点的方法,知道吗?
  • 抱歉回复晚了。上面的代码只定义了一个图结构(V,E),并没有存储元信息,比如根顶点的存在。但是,AddVertex() 返回创建的顶点,因此您可以自己处理。
  • 什么“嵌套模板”?如果您指的是图形属性“协议”,那么它们在很大程度上是不必要的。 BGL 有 Bundled Properties(2009 年可能存在也可能不存在)。我认为这个包装类在现代 BGL/C++ 中的缺点多于优点。我在this new post 中并排演示了它
【解决方案3】:

下面是我用来将一些属性附加到顶点、边和图形的代码。请注意,顶点名称和图形名称是预定义的属性(完整列表请参见 boost/properties.hpp),因此 vertex_name_tgraph_name_t 已经定义。但是,vertex_location_tedge_length_tgraph_notes_t 是我自己的属性,因此需要定义。我从各种示例和文档中拼凑出这段代码,我不确定BOOST_INSTALL_PROPERTY 究竟做了什么,但代码似乎工作正常。

// Define custom properties
enum vertex_location_t { vertex_location };
enum edge_length_t     { edge_length     };
enum graph_notes_t     { graph_notes     };

namespace boost
{
    BOOST_INSTALL_PROPERTY(vertex, location);
    BOOST_INSTALL_PROPERTY(edge,   length  );
    BOOST_INSTALL_PROPERTY(graph,  notes   );
}

// Define vertex properties:  vertex name and location
typedef property<vertex_name_t,     string,
        property<vertex_location_t, Point3> >
VertexProperties;

// Define edge properties:  length
typedef property<edge_length_t, double> EdgeProperties;

// Define graph properties:  graph name and notes
typedef property<graph_name_t,  string,
        property<graph_notes_t, string> >
GraphProperties;

// Define a graph type
typedef adjacency_list
<
    vecS,       // edge container type
    vecS,       // vertex container type
    undirectedS,
    VertexProperties,
    EdgeProperties,
    GraphProperties
> Graph;

【讨论】:

    【解决方案4】:

    我认为 Boost.Graph 有一个非常好的文档,但在这方面并不适合初学者。所以这里有一个例子,我希望它足够简单!

    //includes
    
    // Create a name for your information
    struct VertexInformation
    {
      typedef boost::vertex_property_type type;
    };
    
    // Graph type, customize it to your needs
    // This is when you decide what information will be attached to vertices and/or edges
    // of MyGraph objects
    typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS,
      boost::property<VertexInformation, double> > MyGraph;
    
    int main()
    {
      MyGraph graph;
    
      // Create accessor for information
      typedef boost::property_map<MyGraph, VertexInformation>::type  InformationAccessor;
      InformationAccessor information( get( VertexInformation(), graph ) );
    
      // Create a vertex (for example purpose)
      typedef boost::graph_traits<MyGraph>::vertex_descriptor MyVertex;
      MyVertex vertex = add_vertex( graph );
    
      // Now you can access your information
      put( information, vertex, 1. );
    
      // returns 1 !
      get( information, vertex );
      return 0;
    }
    

    【讨论】:

    • 所以当您将顶点属性模板参数设置为boost::property&lt;VertexInformation, double&gt; 时,您实际上是在“命名”double 顶点属性“VertexInformation”?也就是说,你为什么不把 double value; 放在 VertexInformation 结构里面?
    【解决方案5】:

    我发现这些示例非常有用。在 Windows 上,它将位于您的 \Program Files\boost\boost_1_38\libs\graph\example 目录中。

    kevin_bacon2.cpp 使用顶点属性来存储演员的名字。

    您的顶点和边属性可以存储在常规结构或类中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-01
      • 1970-01-01
      • 2018-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-11
      相关资源
      最近更新 更多