接下來一段日子,會寫一些跟bgl相關的內容。bgl是一個性能很不錯的庫,但是源碼跟鬼畜一樣…文檔也寫得很亂。因爲最近做的論文需要比較好的性能,實在不得不硬着頭皮重新用起bgl。所以儘可能的做一些總結,希望能給後面需要使用的同學能有點幫助。
開始: 一個簡單的小例子
csdn代碼樣式不好看,歡迎直接訪問我的個人網站。
{% codeblock lang:Cpp %}
#include // for std::cout
#include // for std::pair
#include // for std::for_each
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
using namespace boost;
int main(int,char*[])
{
// create a typedef for the Graph type
typedef adjacency_list<vecS, vecS, bidirectionalS> Graph;
// Make convenient labels for the vertices
enum { A, B, C, D, E, N };
const int num_vertices = N;
const char* name = "ABCDE";
// writing out the edges in the graph
typedef std::pair<int, int> Edge;
Edge edge_array[] =
{ Edge(A,B), Edge(A,D), Edge(C,A), Edge(D,C),
Edge(C,E), Edge(B,D), Edge(D,E) };
const int num_edges = sizeof(edge_array)/sizeof(edge_array[0]);
// declare a graph object
Graph g(num_vertices);
// add the edges to the graph object
for (int i = 0; i < num_edges; ++i)
add_edge(edge_array[i].first, edge_array[i].second, g);
return 0;
}
{% endcodeblock %}
基本概念
-
Vertex Descriptors 與 Edge Descriptors
在BGL裏面,我們需要對點和邊進行相應的操作。於是BGL定義了點描述符和邊描述符,也可以稱爲句柄。要對一個點或者邊進行操作,我們需要用過句柄(描述符)進行操作。對於一個圖,要獲取描述符的類型,只能通過一個graph_traits的類進行獲取。graph_traits是對圖類型進行描述的一個類,包含了圖結構的各種信息。
{% codeblock lang:Cpp %}
template bool is_self_loop(typename graph_traits::edge_descriptor e, const Graph& g)
{
typename graph traits::vertex_descriptor u, v;
u = source(e, g);
v = target(e, g);
return u == v;
}
{% endcodeblock %}
上面這個例子是判斷一條邊是不是自環。函數傳進兩個參數,第一個參數是邊的修飾符,第二個參數是圖。line 3創建兩個點修飾符,source和target分別是獲取邊修飾符所代表的邊的首尾兩個頂點的修飾符。最後判斷是否相同。
-
Property Maps
在BGL裏面,另外比較重要的一個結構是Property Maps。這個概念可以理解成點或者邊上的屬性,比如點上可以有attribute(attribute graph),邊上可以有權重。當然,用戶也可以在自己的代碼裏面自己定義,比如存在hashmap。但是BGL提供了這樣一個統一的結構,用戶就可以寫一些可以通用的算法。
{% codeblock lang:Cpp %}
template <typename VertexDescriptor, typename VertexNameMap> void
print_vertex_name(VertexDescriptor v, VertexNameMap name_map)
{
std::cout << get(name_map, v);
}
{% endcodeblock %} -
圖的訪問/遍歷
BGL提供了五種方式對圖的訪問,都是通過迭代器來完成的。
a. 點迭代器(vertex iterator):迭代器裏面的元素是點描述符(點句柄)。
b. 邊迭代器(edge iterator):迭代器裏面的元素是邊描述符(邊句柄)。
c. 出邊迭代器(out-edge iterator)。用來訪問某個點的所有出邊的迭代器,迭代器裏面的元素是邊描述符(邊句柄)。
d. 入邊迭代器(in-edge iterator)。用來訪問某個點的所有入邊的迭代器,迭代器裏面的元素是邊描述符(邊句柄)。
e. 鄰接迭代器(adjacency iterator)。用來訪問一個頂點的所有鄰接點。迭代器裏面的元素是點描述符(點句柄)。
跟描述符一樣,迭代器的類型也是通過graph_traits這個類來確定與獲取。
{% codeblock lang:Cpp %}
template <typename Graph, typename VertexNameMap> void print_vertex_names(const Graph& g, VertexNameMap name_map)
{
std::cout << "vertices(g) = { ";
typedef typename graph traits::vertex iterator_iter t;
for (std::pair<iter_t, iter_t> p = vertices(g);
p.first != p.second; ++p.first)
{
print_vertex_name(*p.first, name_map);
std::cout << ’ ’;
}
std::cout << “}” << std::endl;
}
{% endcodeblock %}
- 圖的創建與修改
下面這個例子添加了五個點,同時添加了七條邊。
a. 添加點
add_vertex 傳入的參數是graph,返回是一個點描述符。
a. 添加邊
add_edge(a, b, g)傳入的參數是首尾兩個點的描述符,第三個參數是要插邊的圖。返回一個tie,tie中第一個元素是邊描述符,第二個元素表示是否成功插入圖中。
{% codeblock lang:Cpp %}
template <typename Graph, typename VertexNameMap, typename TransDelayMap> void build_router_network(Graph& g, VertexNameMap name_map, TransDelayMap delay_map)
{
typename graph traits::vertex descriptor a, b, c, d, e;
a = add_vertex(g); name_map[a] = ’a’;
b = add_vertex(g); name_map[b] = ’b’;
c = add_vertex(g); name_map[c] = ’c’;
d = add_vertex(g); name_map[d] = ’d’;
e = add_vertex(g); name_map[e] = ’e’;
typename graph traits::edge_descriptor ed;
bool inserted;
tie(ed, inserted) = add_edge(a, b, g); delay_map[ed] = 1.2;
tie(ed, inserted) = add_edge(a, d, g); delay_map[ed] = 4.5;
tie(ed, inserted) = add_edge(b, d, g); delay_map[ed] = 1.8;
tie(ed, inserted) = add_edge(c, a, g); delay_map[ed] = 2.6;
tie(ed, inserted) = add_edge(c, e, g); delay_map[ed] = 5.2;
tie(ed, inserted) = add_edge(d, c, g);
delay_map[ed] = 0.4;
tie(ed, inserted) = add_edge(d, e, g);
delay_map[ed] = 3.3;
}
{% endcodeblock %}