图graph
BGL有3种保存图的数据结构,分别是adjacency_list
,adjacency_matrix
和CSR(compressed_sparse_row_graph)
就是中文对应的我觉得是前向星。我觉得CSR挺垃圾的(黑一波),所以尽量不要使用(而且是不是可变图Mutable Graph
,太垃圾了!)。
这里主要介绍adjacency_list
的使用。adjacency_list
的定义有若干个参数
boost::adjacency_list< boost::listS, // 出边的数据类型 boost::vecS, // 保存顶点的数据类型 boost::undirectedS, // 边的类型(单向、双向等) boost::no_property, // 顶点的其他特性(权重,或者ID之类) boost::no_property, // 边的其他特性 boost::no_property, // 图对象的特性 boost::listS> // 保存边的容器类型(暂时不知道和第一个参数是否冲突或类似)
图有顶点vertex,和边edge。我们可以自定义两种数据类型。
namespace udi{ struct TopoVertexProperty{ //自定义顶点 //std::string label; int32_t vertex_id; float position_x; float position_y; float position_z; struct qqq{int xyz;}gg; }; struct TopoEdgeProperty{ //自定义边 public: float weight = 1; //边的信息 float weight2 = 3; //边的信息 struct Test{ //边的信息,假设权重是自定义类型Test int x=1; int y=1; } w; struct less { bool operator() (const Test& x, const Test & y) const { return x.x<y.x; } typedef Test first_argument_type; typedef Test second_argument_type; typedef bool result_type; }; struct closed_plus//保证加法不越界 { const Test inf; closed_plus() : inf({10000,10000}) { } closed_plus(Test inf) : inf(inf) { } Test operator()(const Test& a, const Test& b) const { using namespace std; if (a.x == inf.x && a.y == inf.y) return inf; if (b.x == inf.x && b.y == inf.y) return inf; return {a.x+b.x,a.y+ b.y}; } }; friend std::ostream& operator << (std::ostream& x, const Test q); }; std::ostream& operator << (std::ostream& x, const udi::TopoEdgeProperty::Test q){ return x<<"("<<q.x<<" ,"<<q.y<<")"; }
那么定义的图的方法如下
typedef boost::adjacency_list<boost::listS , //边的保存方案,用list boost::vecS , //点的保存方案,用vector,可以下标访问 boost::directedS , //undirectedS udi::TopoVertexProperty, //自定义vertex udi::TopoEdgeProperty> Graph; //自定义edge typedef Graph::edge_descriptor EdgeDescriptor; //描述边的类型 typedef Graph::vertex_descriptor VertexDescriptor; //描述点的类型 Graph g;
添加点的方法如下
VertexDescriptor v1 = boost::add_vertex(udi::TopoVertexProperty(), g); //可以直接带上数值来直接给点赋值。 VertexDescriptor v2 = boost::add_vertex(g); VertexDescriptor v3 = boost::add_vertex(g); VertexDescriptor v4 = boost::add_vertex(g); VertexDescriptor v5 = boost::add_vertex(g); //给顶点赋值 //集合赋值法 auto vertexs = boost::get(&udi::TopoVertexProperty::gg, g); //得到的是g里所有顶点里gg的属性的集合 vertexs[v1].xyz= 5; //直接赋值 //直接访问的方法给顶点赋值 g[v1].vertex_id = 0; g[v1].position_x = 11; g[v1].position_y = 111; g[v1].position_z = 11111111; g[v2].vertex_id = 1; g[v2].position_x = 22; g[v2].position_y = 222; g[v2].position_z = 22222222; g[v3].vertex_id = 2; g[v3].position_x = 33; g[v3].position_y = 333; g[v3].position_z = 33333333; g[v4].vertex_id = 3; g[v4].position_x = 44; g[v4].position_y = 444; g[v4].position_z = 44444444; g[v5].vertex_id = 4; g[v5].position_x = 55; g[v5].position_y = 555; g[v5].position_z = 55555555;
添加边与给边赋值的方法
auto q = boost::add_edge(1,4,udi::TopoEdgeProperty(), g); //std::pair<EdgeDescriptor , bool> EdgeDescriptor e; bool bbb; boost::tie(e,bbb) = boost::add_edge( v1 , v2 , udi::TopoEdgeProperty(), g); std::pair<EdgeDescriptor , bool> e21 = boost::add_edge(v2 , v1 , g); std::pair<EdgeDescriptor , bool> e23 = boost::add_edge(v2 , v3 , g); std::pair<EdgeDescriptor , bool> e34 = boost::add_edge(v3 , v4 , g); std::pair<EdgeDescriptor , bool> e41 = boost::add_edge(v4 , v1 , g); std::pair<EdgeDescriptor , bool> e13 = boost::add_edge(v1 , v2 , g); std::pair<EdgeDescriptor , bool> e25 = boost::add_edge(v2 , v5 , g); g[q.first].weight = 4;
输出调试信息,边,点等信息。
std::cout << "Graph:" << std::endl; boost::print_graph(g , boost::get( &udi::TopoVertexProperty::vertex_id, g) ); //上面的print_graph函数,并不能特别优雅的进行输出...也许我方法不对。 std::cout << "num_vertex:" << boost::num_vertices(g) << std::endl; std::cout << "num_edges:" << boost::num_edges(g) << std::endl;
Dijkstra方法求最短路
boost::graph_traits<Graph>::vertex_iterator it; auto index_map = boost::get(boost::vertex_index, g); std::vector<VertexDescriptor > predecessor_map(num_vertices(g)); std::vector<udi::TopoEdgeProperty::Test> distances(boost::num_vertices(g));//距离数组的类型,必须和权重的类型一致。这里我们用的是Test类型(大多数时候是float之类的) auto distance_iterator = boost::make_iterator_property_map(distances.begin() , boost::get(boost::vertex_index , g)); source = boost::vertex(1,g); boost::dijkstra_shortest_paths(g, source, &predecessor_map[0], distance_iterator,//&distances[0]都行吗? boost::get(&udi::TopoEdgeProperty::w ,g), //weight index_map, udi::TopoEdgeProperty::less(), udi::TopoEdgeProperty::closed_plus(), udi::TopoEdgeProperty::Test({10000,10000}), //inf udi::TopoEdgeProperty::Test({0,0}), //zero boost::default_dijkstra_visitor() ); //输出调试信息 std::cout << "distances and parents:" << std::endl; Graph::vertex_iterator vi, vend; for (boost::tie(vi, vend) = boost::vertices(g); vi != vend; ++ vi) { std::cout << "distance(" << g[*vi].vertex_id <<")=" << distances[*vi] << ","; std::cout << "parent(" << g[*vi].vertex_id <<")=" << g[predecessor_map[*vi]].vertex_id<< std::endl; }
有时候不是自定义类型,是系统类型为权重(比如float,double等),耶就是说不需要提供比较器之类的东西,此时可以用下面的方法来进行求解Dijkstra最短路。
//以float为例 boost::graph_traits<Graph>::vertex_iterator it; source = boost::vertex(1,g); std::vector<float> distances(boost::num_vertices(g)); auto weight_map=boost::weight_map(boost::get(&udi::TopoEdgeProperty::weight ,g)); auto index_map = boost::get(boost::vertex_index, g); std::vector<VertexDescriptor > predecessor_map(num_vertices(g)); auto distance_iterator = boost::make_iterator_property_map(distances.begin() , boost::get(boost::vertex_index , g)); boost::dijkstra_shortest_paths(g, source, weight_map. distance_map(distance_iterator). predecessor_map(&predecessor_map[0]));