C++圖常用庫boost graph library

接下來一段日子,會寫一些跟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 %}

基本概念

  1. 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分別是獲取邊修飾符所代表的邊的首尾兩個頂點的修飾符。最後判斷是否相同。

  1. 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 %}

  2. 圖的訪問/遍歷

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 %}

  1. 圖的創建與修改

下面這個例子添加了五個點,同時添加了七條邊。

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 %}

資源

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章