图论是一种数学抽象,它对于解决多种计算机科学问题是非常有用的,Boost.Graph提供了一个基于图论的通用编程接口.
Boost.Graph是一个图的封装,在《数据结构》的教科书里,一般都会讲到数组、链表、队列、堆栈、堆、树、图论等。其中前面几个已经在C++标准库(STL)中实现了(如vector,list,stack,queue,heap等),却没有提供一个与树或图对应的实现,实在说不过去。于是这个艰巨而又光荣的任务就落到了作为标准库的预备役的Boost身上, Boost.Graph诞生啦!
Boost.Graph分成数据结构和算法两个大部分(为了便于区分,后文称"图结构"和"图算法"),其中"图结构"相当于 STL里的容器,自带了邻接表(adjacency_list)、邻接矩阵(adjacency_matrix)和CSR图(compressed_sparse_row_graph)三种。“图算法”相当于STL里的算法,就象std::sort不能用于std::list 一样,对于不同的“图结构”,“图算法”也有不同的适用范围。
“图算法”的适用范围按“概念(Concept)”划分,“图结构”根据它的结构特点被分为“可变图”、“关联图”、“双向图”、“邻接图”、“点表 图”、“边表图”、“属性图”、“可变属性图”几个概念。一种“图结构”可能支持其中的一部分概念而不支持其它的概念,于是也就决定了这种“图结构”所支 持的“图算法”。

图的概念以及对应的算法:

表格中g为图对象,u,v为源和目标顶点,e为边,iter为边的迭代器类型,p为谓词函数(或函数对象)

概念 Concept 支持函数
可变图(Mutable Graph)
允许添加、删除顶点和边
std::pair<edge_descriptor,bool>
    add_edge(u, v, g);
加入一条边,返回加入后的边以及是否成功。
(若边已存在且不允许并行边,则返回已存在的边)
void remove_edge(u, v, g); 删除连接u和v的边
void remove_edge(e, g); 同上
void remove_edge(iter, g); 同上
void remove_edge_if(p, g); 删除所有谓词p为true的边
void remove_out_edge_if(u, p, g); 删除所有谓词p为ture的出边
void remove_in_edge_if(u, p, g); 删除所有谓词p为trre的入边
vertex_descriptor add_vertex(g); 添加一个顶点,返回加入的顶点
void clear_vectex(u, g); 删除u上的所有边
void remove_vectex(u, g); 删除顶点u,注意删除顶点之前要确保该顶点没有边与之连接,否则会出现未定义的行为。典型的用法是在 remove_vectex前调用clear_vectex。
关联图(Incidence Graph)
vertex_descriptor source(e, g); 返回e边上的起源顶点
vertex_descriptor target(e, g); 返回e边上的目标顶点
std::pair<out_edge_iterator, out_edge_iterator>
    out_edges(u, g);
以边迭代器对的形式返回顶点u上的所有出边
degree_size_type out_degree(u, g); 返回顶点u的出度
双向图(Bidirectional Graph)
std::pair<in_edge_iterator, in_edge_iterator>
    in_edges(v, g)
以边迭代器对的形式返回顶点v上的所有入边
degree_size_type in_degree(v, g) 返回顶点v的入度
degree(v, g) 返回入度+出度
邻接图(Adjacency Graph)
std::pair<adjacency_iterator, adjacency_iterator>
    adjacent_vertices(v, g)
以顶点迭代器范围的形式返回顶点v上的所有邻接点。
点表图(Vertex List Graph)
std::pair<vertex_iterator, vertex_iterator>
    vertices(g)
以顶点迭代器范围的形式返回所有顶点
vertices_size_type num_vertices(g) 返回顶点数
边表图(Edge List Graph)
std::pair<edge_iterator, edge_iterator>
    edges(g);
以边迭代器的形式返回所有边
edges_size_type num_edges(g); 返回边数
vertex_descriptor source(e, g); 返回e边上的起源顶点
vertex_descriptor target(e, g); 返回e边上的目标顶点
属性图(Property Graph)
可以为每个顶点和边加入附加属性
get(p, g) 得到图g的属性p的值
get(p, g, x) 得到顶点或边x的属性p的值
put(p, g, x, v) 设置属性值
可变属性图(Mutable Property Graph)
std::pair<edge_descriptor, bool>
    add_edge(u, v, ep, g)
加入边,顺便给属性ep赋值
vertex_descriptor add_vertex(vp, g) 加入顶点,顺便给属性vp赋值

Boost.Graph的三个图结构

邻接表(adjacency_list)

邻接表为每个顶点维护一份线性表(数组、链表等),表中的每个节点就是与该顶点相连的其它顶点(见下图)。这种方式比较方便添加删除顶点和边,扩展性比较强(所以它支持前文中所有图概念),但是查询的速度不及后面将讲的另外两个。

类声明:

adjacency_list<OutEdgeList, VertexList, Directed, VertexProperties, EdgeProperties, GraphProperties, EdgeList>

前两个模版参数(OutEdgeList,VertexList)分别表示每个顶点出边集合的数据结构和图中顶点集合的数据结构,可选的有:

参数 选用的数据结构
vecS std::vector
listS std::list
slistS std::slist
setS std::set
multisetS std::multiset
hash_setS std::hash_set

可以根据使用方式决定选择哪种数据结构,比如经常插入删除使用listS,经常遍历使用vecS。

第三个参数(Directed)表示图的形式,可选项有:

参数 表示形式
bidirectionalS 表示一个既有出边也有入边的有向图
directedS 表示一个只能存取出边的有向图
undirectedS 表示一个无向图

构造函数:

  1. adjacency_list()
  2. //建立一个空的邻接表
  3. adjacency_list(vertices_size_type n,
  4. const GraphProperty& p = GraphProperty())
  5. //建立包含n个顶点的邻接表
  6. template <class EdgeIterator>
  7. adjacency_list(EdgeIterator first, EdgeIterator last,
  8. vertices_size_type n,
  9. edges_size_type m = 0,
  10. const GraphProperty& p = GraphProperty())
  11. //建立由first~last的边及包含n个顶点的邻接表
  12. template <class EdgeIterator, class EdgePropertyIterator>
  13. adjacency_list(EdgeIterator first, EdgeIterator last,
  14. EdgePropertyIterator ep_iter,
  15. vertices_size_type n,
  16. vertices_size_type m = 0,
  17. const GraphProperty& p = GraphProperty())
  18. //同上,顺便给边的属性赋值

成员方法:

  1. void clear()
  2. //清空边和顶点
  3. void swap(adjacency_list& x)
  4. //交换

定义于头文件:<boost/graph/adjacency_list.hpp>

邻接矩阵(adjacency_matrix)

邻接矩阵用一个[顶点数*顶点数]的矩阵存放连接各顶点的边,如图所示:

类声明:

adjacency_matrix<Directed, VertexProperty, EdgeProperty, GraphProperty, Allocator>

邻接矩阵对边的查找、添加、删除都非常快,缺点是占用内存空间比较大,是顶点数的平方,而且对顶点数的添加删除就不行了。所以比较适合于顶点少边多而且不须要添加删除顶点的场合。

构造函数:

  1. adjacency_matrix()
  2. //建立一个空的邻接矩阵
  3. adjacency_matrix(vertices_size_type n,
  4. const GraphProperty& p = GraphProperty())
  5. //建立包含n个顶点的邻接矩阵

定义于头文件:<boost/graph/adjacency_matrix.hpp>

CSR图(compressed_sparse_row_graph)

这种图以CSR的格式存储邻接矩阵,CSR格式是一种矩阵存储形式,它由三个数组组成(假定取名 values,columns,rowIndex):数组 values存放矩阵中的有效数据,数组columns存放数组values中各数据于矩阵中所在的列,数组rowIndex存放矩阵中各行的第一个有效 数据在数组values上的索引位。比如下面的矩阵:

则CSR的三个数组为:


values = (1 -1 -3 -2 5 4 6 4 -4 2 7 8 -5)
columns = (1 2 4 1 2 3 4 5 1 3 4 2 5)
rowIndex = (1 4 6 9 12 14)              

这种存储形式显然更适用于稀疏矩阵,而且增加删除边和顶点都要重建三个数组。所以在Graph库 中,compressed_sparse_row_graph不属于可变图 (Mutable Graph)概念,即前文中可变图概念的函数都不能用。它适于图比较大而且图结构不会改变的场合。

构造函数:

构造函数与邻接表相同,成员方法中没有clear、swap等修改图结构的方法。并且不支持可变图概念的函数,对于图结构(边与顶点的关系)是只读的,不过属性是可以存取的。

头文件定义于<boost/graph/compressed_sparse_row_graph.hpp>

示例:生成一个图,并显示出图中所有顶点和边

假设我们要生成下面这个图

这是一个有向图

顶点是:A B C D E F

所有的边:

B --> C B --> F C --> C C --> A D --> E E --> D F --> A

由于Boost.Graph的顶点只能使用整型(放心,后文会说怎样把自定义的数据绑定到节点和边上的),所以我们把A~F依次按0~5编号。这样,所有的顶点和边就是:

0,1,2,3,4,5 1 --> 2 1 --> 5 2 --> 2 2 --> 0 3 --> 4 4 --> 3 5 --> 0

代码:

  1. #include <iostream>
  2. #include <utility>
  3. #include <boost/graph/graph_traits.hpp>
  4. #include <boost/graph/adjacency_list.hpp>
  5. using namespace std;
  6. using namespace boost;
  7. int main(int argc, char* argv[])
  8. {
  9. // 定义图类型,使用vector存放顶点和边,有向图
  10. typedef adjacency_list<vecS, vecS, directedS> graph_t;
  11. // 产生图对象,有6个顶点
  12. graph_t g(6);
  13. // 加入边
  14. add_edge(1,2,g);
  15. add_edge(1,5,g);
  16. add_edge(2,2,g);
  17. add_edge(2,0,g);
  18. add_edge(3,4,g);
  19. add_edge(4,3,g);
  20. add_edge(5,0,g);
  21. // 显示所有的顶点
  22. // 顶点迭代器类型
  23. typedef graph_traits<graph_t>::vertex_iterator vertex_iter;
  24. // 得到所有顶点,vrange中的一对迭代器分别指向第一个顶点和最后的一个顶点之后。
  25. std::pair<vertex_iter, vertex_iter> vrange = vertices(g);
  26. for(vertex_iter itr=vrange.first; itr!=vrange.second; ++itr)
  27. cout << *itr << endl;
  28. // 显示所有的边
  29. // 边迭代器类型
  30. typedef graph_traits<graph_t>::edge_iterator edge_iter;
  31. // 得到所有边,erange中的一对迭代器分别指向第一条边和最后的一条边之后
  32. std::pair<edge_iter, edge_iter> erange = edges(g);
  33. for(edge_iter itr=erange.first; itr!=erange.second; ++itr)
  34. cout << source(*itr,g) << "-->" << target(*itr,g) << endl;
  35. return 0;
  36. };

编译运行,显示结果应该和之前说的顶点和边一致。可以修改本例中的图类型试试,如typedef adjacency_matrix<directedS> graph_t;

为了便于理解,上面的代码没有使用任何技巧来简化代码。实际上在官方的Graph实例中,使用了enum来代替代表顶点的整数,使用boost::tie来简化for循环,理解了上面的代码后,再看这个优化版的代码就好看多了:

  1. #include <iostream>
  2. #include <utility>
  3. #include <boost/graph/graph_traits.hpp>
  4. #include <boost/graph/adjacency_list.hpp>
  5. using namespace std;
  6. using namespace boost;
  7. int main(int argc, char* argv[])
  8. {
  9. // 定义图类型
  10. typedef adjacency_list<vecS, vecS, directedS> graph_t;
  11. // 顶点
  12. enum{A,B,C,D,E,F,N}; //N正好等于顶点数
  13. // 边
  14. typedef std::pair<int, int> edge_t;
  15. edge_t edgelist[]={
  16. edge_t(B,C),
  17. edge_t(B,F),
  18. edge_t(C,C),
  19. edge_t(C,A),
  20. edge_t(D,E),
  21. edge_t(E,D),
  22. edge_t(F,A)
  23. };
  24. // 产生图对象,输入边迭代器和N个顶点
  25. graph_t g(edgelist, edgelist+7, N);
  26. // 显示所有的顶点
  27. graph_traits<graph_t>::vertex_iterator vitr, vitr_end;
  28. for(tie(vitr, vitr_end) = vertices(g);
  29. vitr != vitr_end;
  30. ++vitr)
  31. cout << *vitr << endl;
  32. // 显示所有的边
  33. graph_traits<graph_t>::edge_iterator eitr, eitr_end;
  34. for(tie(eitr, eitr_end) = edges(g);
  35. eitr != eitr_end;
  36. ++eitr)
  37. cout << source(*eitr,g) << "-->" << target(*eitr,g) << endl;
  38. return 0;
  39. }

在本例中,有一个graph_traits类是前文中没有提到的。它是用于提取出与图相关的类型的,它的声明为:

  1. template <typename Graph>
  2. struct graph_traits {
  3. typedef typename Graph::vertex_descriptor      vertex_descriptor;
  4. typedef typename Graph::edge_descriptor        edge_descriptor;
  5. typedef typename Graph::adjacency_iterator     adjacency_iterator;
  6. typedef typename Graph::out_edge_iterator      out_edge_iterator;
  7. typedef typename Graph::in_edge_iterator       in_edge_iterator;
  8. typedef typename Graph::vertex_iterator        vertex_iterator;
  9. typedef typename Graph::edge_iterator          edge_iterator;
  10. typedef typename Graph::directed_category      directed_category;
  11. typedef typename Graph::edge_parallel_category edge_parallel_category;
  12. typedef typename Graph::traversal_category     traversal_category;
  13. typedef typename Graph::vertices_size_type     vertices_size_type;
  14. typedef typename Graph::edges_size_type        edges_size_type;
  15. typedef typename Graph::degree_size_type       degree_size_type;
  16. };

其中每个成员的定义是:

成员 说明
vertex_descriptor 用于区分图中各顶点的对象类型
edge_descriptor 用于区分图中各边的对象类型
adjacency_iterator 用于遍历邻接点的迭代器
out_edge_iterator 用于遍历出边的迭代器
in_edge_iterator 用于遍历入边的迭代器
vertex_iterator 用于遍历图中的顶点的迭代器
edge_iterator 用于遍历图中边的迭代器
directed_category 指出该图是有向图还是无向图
edge_parallel_category 指出该图是否允许输入平行边(可插入平等边allow_parallel_edge_tag或可自动去除平行边disallow_parallel_edge_tag)
traversal_category 指出怎样遍历图中的顶点,可选的有incidence_graph_tag, adjacency_graph_tag, bidirectional_graph_tag, vertex_list_graph_tag, edge_list_graph_tag, vertex_and_edge_list_graph_tag, adjacency_matrix_tag.你也可以通过继承上面这些标记来建立自己的标记
vertices_size_type 用于表示图中顶点数的无符号整型
edge_size_type 用于表示图中边数的无符号整型
degree_size_type 用于表示顶点度数的无符号整型

用法:

  1. //获得边类型
  2. typedef boost::graph_traits<G>::edge_descriptor edge_t;
  3. //获得顶点类型
  4. typedef boost::graph_traits<G>::vertex_descriptor vertex_t;
  5. //获得出边迭代器
  6. typedef boost::graph_traits<G>::out_edge_iterator oedge_t;

Boost Graph相关推荐

  1. boost::graph::distributed::mpi_process_groupboost::graph::用法的测试程序

    boost::graph::distributed::mpi_process_groupboost::graph::用法的测试程序 实现功能 C++实现代码 实现功能 boost::graph::di ...

  2. boost::graph::distributed::hohberg_biconnected_components用法的测试程序

    boost::graph::distributed::hohberg_biconnected_components用法的测试程序 实现功能 C++实现代码 实现功能 boost::graph::dis ...

  3. boost::graph::distributed::distributed_queue用法的测试程序

    boost::graph::distributed::distributed_queue用法的测试程序 实现功能 C++实现代码 实现功能 boost::graph::distributed::dis ...

  4. boost::graph::page_rank用法的测试程序

    boost::graph::page_rank用法的测试程序 实现功能 C++实现代码 实现功能 boost::graph::page_rank用法的测试程序 C++实现代码 #include < ...

  5. boost::graph::dimacs_basic_reader用法的测试程序

    boost::graph::dimacs_basic_reader用法的测试程序 实现功能 C++实现代码 实现功能 boost::graph::dimacs_basic_reader用法的测试程序 ...

  6. boost::graph模块实现分布式压缩稀疏行图类型的测试

    boost::graph模块实现分布式压缩稀疏行图类型的测试 实现功能 C++实现代码 实现功能 boost::graph模块实现分布式压缩稀疏行图类型的测试 C++实现代码 #include < ...

  7. boost::graph::distributed用法的测试程序

    boost::graph::distributed用法的测试程序 实现功能 C++实现代码 实现功能 boost::graph::distributed用法的测试程序 C++实现代码 #include ...

  8. boost::graph模块实现广度优先搜索算法的使用示例

    boost::graph模块实现广度优先搜索算法的使用示例 实现功能 C++实现代码 实现功能 boost::graph模块实现广度优先搜索算法的使用示例 C++实现代码 #include <b ...

  9. boost::graph::isomorphism用法的测试程序

    boost::graph::isomorphism用法的测试程序 实现功能 C++实现代码 实现功能 boost::graph::isomorphism用法的测试程序 C++实现代码 #include ...

  10. boost::graph模块实现Graphviz DOT 语言阅读器

    boost::graph模块实现Graphviz DOT 语言阅读器 实现功能 C++实现代码 实现功能 boost::graph模块实现Graphviz DOT 语言阅读器 C++实现代码 #def ...

最新文章

  1. Jersey Restful Application with tomcat
  2. Python中单元测试出错了,会怎么样?
  3. DTO – 服务实现中的核心数据
  4. 自己动手写spring(三) 支持注解方式
  5. 美团面试一道场景设计题
  6. 第8章 函数探索
  7. python数据框拼接_pandas数据拼接的实现示例
  8. Ubuntu为julia安装深度学习框架MXNet(支持CUDA和OPenCV编译)
  9. (转)比特币王国的内战与分裂|《财经》特稿
  10. Golang 编译成DLL文件
  11. 同一网络俩台计算机连接,两台电脑如何连接在同一个局域网呢
  12. html单元格边框斜线,excel表头三斜线 将线条的两端放在单元格的边框上
  13. SOX的一些命令和kaldi使用sox音频数据增强
  14. 使用GHOST对Windows操作系统进行备份和还原
  15. java实例化类之后如何赋值_深入理解Java对象的创建过程:类的初始化与实例化...
  16. 实验 5 递归与列表
  17. 联想拯救者2020R7000双系统装机记录_自用
  18. 「趣小面」寻融资:前景美好,“钱”景难说
  19. 安徽航信研发项目管理体系探索与实践
  20. 服务器搭建SSH暴力攻击诱饵,制作密码字典

热门文章

  1. 标准C字符和字符串函数
  2. Python Imaging Library: ImageChops Module(图像通道操作模块)
  3. 集成产品开发过程及其概念模型
  4. 拖拽上传及读取文件实现
  5. 《面向机器智能的TensorFlow实践》一 2.8 测试TensorFlow、Jupyter Notebook及matplotlib...
  6. dd wipe 命令磁盘清空shell脚本,笔记本台机MAC通用
  7. Struts入门经验(二)
  8. OpenCV-尺寸调整cv::resize
  9. linux异常级别,linux性能异常定位之进程级别
  10. linux bsd命令,科学网—Linux/BSD下join命令使数据以tab为分隔符的方法 - 李雷廷的博文...