boost graph lib记录
简单记录一下BGL库的使用
1 BGL库的数据结构
BGL有三种数据结构:
The BGL currently provides two graph classes and an edge list adaptor:
一般只用邻接表
1.1 邻接表
如何使用 adjacency_list
class 的教程在这:Using adjacency_list
.
创建一个邻接表需要使用类模板:
adjacency_list<OutEdgeList, VertexList, Directed,
VertexProperties, EdgeProperties,
GraphProperties, EdgeList>
Parameter | Description | Default |
---|---|---|
OutEdgeList | The selector for the container used to represent the edge-list for each of the vertices. | vecS |
VertexList | The selector for the container used to represent the vertex-list of the graph. | vecS |
Directed | A selector to choose whether the graph is directed, undirected, or directed with bidirectional edge access (access to both out-edges and in-edges). The options are directedS , undirectedS , and bidirectionalS . | directedS |
VertexProperties | for specifying internal property storage. | no_property |
EdgeProperties | for specifying internal property storage. | no_property |
GraphProperties | for specifying property storage for the graph object. | no_property |
EdgeList | The selector for the container used to represent the edge-list for the graph. | listS |
(1)OutEdgeList和VertexList
OutEdgeList和VertexList,它们控制用于表示图形的底层数据结构(使用std的vector,list之类)。OutEdgeList和VertexList的选择会影响图形操作的时间复杂度和空间复杂度。
vecS
selectsstd::vector
.listS
selectsstd::list
.slistS
selectsstd::slist
.setS
selectsstd::set
.multisetS
selectsstd::multiset
.hash_setS
selectsboost::unordered_set
.
通常,如果需要快速添加和删除顶点,列表是一个不错的选择。与选择vec相比,这样做的代价是额外的空间开销。
Directed有directedS
, undirectedS
, and bidirectionalS
几个选项。这区分了无向图(undirectedS)和有向图(bidirectionalS,directedS
),其中bidirectionalS可以调用in_edges(),out_edges()函数。
(2)Internal Properties
属性表示了图中顶点和边的属性,BGL中建议使用捆绑属性 bundled properties。
以城市(顶点)与路网(边)的关系为例子,可以给点和边定义属性,如何定义BGL中的图:
struct City
{
string name;
int population;
vector<int> zipcodes;
};
struct Highway
{
string name;
double miles;
int speed_limit;
int lanes;
bool divided;
};
typedef boost::adjacency_list<
boost::listS, boost::vecS, boost::bidirectionalS,
City, Highway>
Map;
访问图中顶点和边的方式如下:
Map map; // load the map
Map::vertex_descriptor v = *vertices(map).first;
map[v].name = "Troy";
map[v].population = 49170;
map[v].zipcodes.push_back(12180);
Map::edge_descriptor e = *out_edges(v, map).first;
map[e].name = "I-87";
map[e].miles = 10.;
map[e].speed_limit = 65;
map[e].lanes = 4;
map[e].divided = true;
**(3)稳定性 **
某些操作会导致顶点或边的描述符无效,需要注意。
Some care must be taken when changing the structure of a graph (via adding or removing edges). Depending on the type of adjac
ency_list
and on the operation, some of the iterator or descriptor objects that point into the graph may become invalid.
In general, if you want your vertex and edge descriptors to be stable (never invalidated) then use listS
or setS
for the VertexList
and OutEdgeList
template parameters of adjacency_list
. If you are not as concerned about descriptor and iterator stability, and are more concerned about memory consumption and graph traversal speed, use vecS
for the VertexList
and/or OutEdgeList
template parameters.
Table: Summary of Descriptor and Iterator Invalidation.
Function | Vertex Desc | Edge Desc | Vertex Iter | Edge Iter | Adj Iter |
---|---|---|---|---|---|
add_edge() | OK | OK | OK | EL=vecS &&Directed=directedS | EL=vecS |
remove_edge() remove_edge_if() remove_out_edge_if() remove_in_edge_if() clear_vertex() | OK | OK | OK | EL=vecS &&Directed=directedS | EL=vecS |
add_vertex() | OK | OK | OK | VL=vecS &&Directed=directedS | VL=vecS &&Directed=directedS |
remove_vertex() | VL=vecS | VL=vecS | VL=vecS | VL=vecS | VL=vecS |
代码
由于资料不够清楚且例子较少,BGL实在是不好用,vertex设置为listS时无法得知怎么设置 boost::make_iterator_property_map,只能设置为vector。
“pathMap.h”
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/properties.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/named_function_params.hpp>
#include <iostream>
#include <vector>
#include <utility> // for std::pair
#include <algorithm> // for std::for_each
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
struct VertexData
{
std::string first_name;
int num;
};
struct EdgeData
{
std::string edge_name;
double dist;
};
namespace pathPlan {
struct vertexData {
std::string name;
bool omni;
float x;
float y;
float theta;
};
struct edgeData {
bool omni;
float weight;
float theta;
std::string right_node, left_node;
};
typedef boost::adjacency_list< boost::listS, boost::vecS, boost::undirectedS,
vertexData, edgeData > pathGraph;
typedef boost::graph_traits<pathGraph>::vertex_descriptor path_vertex_descriptor;
typedef boost::graph_traits<pathGraph>::edge_descriptor path_edge_descriptor;
class graphPath {
public:
std::string path_id;
pathGraph pathG;
std::map<std::string,vertexData> all_vertex;
std::vector<edgeData> all_edge;
graphPath(const std::map<std::string,vertexData> &all_vertex1, const std::vector<edgeData> &all_edge1);
// get shortest path
bool getShortestPath( std::string start_name, std::string end_name, std::vector<std::string> &path );
private:
std::map< std::string, path_vertex_descriptor> vertexID2descriptor;
// generate graph
bool generate_graph();
};
void input_data( std::map<std::string,vertexData> &all_vertex, std::vector<edgeData> &all_edge );
}
“pathMap.cpp”
#include "pathMap.h"
#include <iostream>
using namespace pathPlan;
using namespace boost;
graphPath::graphPath(const std::map<std::string, vertexData> &all_vertex1, const std::vector<edgeData> &all_edge1) :
all_vertex(all_vertex1), all_edge(all_edge1) {
// check input
// generate
generate_graph();
}
bool graphPath::generate_graph() {
std::map<std::string, vertexData>::iterator iter;
// add vertex
for (iter = all_vertex.begin(); iter != all_vertex.end(); ++iter) {
path_vertex_descriptor ds = boost::add_vertex(iter->second, pathG);
vertexID2descriptor.insert(std::make_pair(iter->second.name, ds));
std::cout << " name = " << iter->second.name << " descri = " << ds << std::endl;
}
// add edge
std::vector<edgeData>::iterator iter2;
for (iter2 = all_edge.begin(); iter2 != all_edge.end(); ++iter2) {
boost::add_edge(vertexID2descriptor[iter2->left_node], vertexID2descriptor[iter2->right_node], *iter2, pathG);
}
//
std::cout << " size edge = " << boost::num_edges(pathG) << std::endl;
std::cout << " size vertex = " << boost::num_vertices(pathG) << std::endl;
return true;
}
bool graphPath::getShortestPath(std::string start_name, std::string end_name, std::vector<std::string> &path) {
path_vertex_descriptor R, L;
L = vertexID2descriptor[start_name];
R = vertexID2descriptor[end_name];
pathGraph pathG1;
std::vector<path_vertex_descriptor> p(num_vertices(pathG));
std::vector<path_edge_descriptor> q(num_vertices(pathG));
std::vector<float> d(num_vertices(pathG));
auto distance_iterator = boost::make_iterator_property_map(d.begin(), boost::get(boost::vertex_index, pathG));
boost::dijkstra_shortest_paths(pathG, L, predecessor_map(&p[0]).
weight_map(boost::get(&edgeData::weight, pathG)).
distance_map(distance_iterator));
std::cout << " d size = " << d.size() << std::endl;
graph_traits<pathGraph>::vertex_iterator vi, vend;
for (boost::tie(vi, vend) = boost::vertices(pathG); vi != vend; ++vi) {
std::cout << "distance(" << pathG[*vi].name << ") = " << d[*vi] << ", ";
std::cout << "parent(" << pathG[*vi].name << ") = " << pathG[p[*vi]].name << std::endl;
}
/*
path_vertex_descriptor vi,vend;
for (boost::tie(vi, vend) = boost::vertices(pathG); vi != vend; vi++ ) {
std::cout<<" d "<< vi<<" = "<< d[vi] << " , "<<p[vi] << std::endl ;
}
*/
/*
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]));
*/
}
void pathPlan::input_data(std::map<std::string, vertexData> &all_vertex, std::vector<edgeData> &all_edge) {
all_vertex.clear();
all_edge.clear();
vertexData v;
for (int i = 0; i < 12; ++i) {
v.name = std::to_string(i);
v.omni = false;
v.theta = 0;
v.x = 0.5 * i;
v.y = i;
all_vertex.insert(std::make_pair(v.name, v));
}
edgeData e;
for (int i = 0; i < 10; ++i) {
e.theta = 0;
e.left_node = std::to_string(i);
e.right_node = std::to_string(i + 1);
e.omni = false;
e.weight = 1;
all_edge.push_back(e);
}
}
int
main(int, char *[])
{
std::map<std::string,vertexData> all_vertex;
std::vector<edgeData> all_edge;
input_data( all_vertex, all_edge );
graphPath pG(all_vertex, all_edge);
std::vector<std::string> path;
pG.getShortestPath( "1", "4", path);
}
cmakelists
cmake_minimum_required (VERSION 2.9)
project (test)
find_package(Boost COMPONENTS regex system REQUIRED)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/include
)
#add_executable(test src/pathMap.cpp)