数据结构——图

一、图的概念

图(graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合
在图中,数据元素称为顶点(vertex)。在图中,任意两个顶点之间都有可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的。
若顶点vi到vj之间的边没有方向,则称这条边为无向边(edge),用无序偶对(vi,vj)来表示。
若从顶点vi到vj的边有方向,则称这条边为有向边,也称为弧(arc)。用有序偶来表示,vi称为弧尾(tail),vj称为弧头(head)。
无向边用小括号“()”表示,而有向边则用尖括号“<>”表示
在图中,若不存在顶点到其自身的边,且同一条边不重复出现,则称这样的图为简单图。
在无向图中,如果任意两个顶点之间都存在边,则称该图为无向完全图。
在有向图中,如果任意两个顶点之间都存在方向互为相反的两条弧,则称该图为有向完全图
有很少条边或弧的图称为稀疏图,反之称为稠密图。
与图的边或弧相关的数叫做权(weight)。带权的图通常称为网(network)。
假设有两个图G=(V,{E})和G’=(V’,{E’}),如果V’是V的子集,且E’是E的子集,则称G’为G的子图(subgraph)。

对于无向图G=(V,{E}),如果边(v,v’)∈E,则称顶点v和v’互为邻接点(adjacent),即v和v’相邻接。边(v,v’)依附(incident)于顶点v和v’,或者说(v,v’)与顶点v和v’相关联。顶点v的度(degree)是和v相关联的边的数目,记为TD(v)。
对于有向图,以顶点v为头的弧的数目称为v的入度(inDegree),记为ID(v);以v为尾的弧的数目称为v的出度(outDegree),记为OD(v);顶点v的度为TD(v)=ID(v)+OD(v)。
无向图G=(V,{E})中从顶点v到顶点v’的路径(path)是一个顶点序列(v=vi,0,vi,1,…,vi,m=v’),其中(vi,j-1,vi,j)∈E,1≤j≤m。
路径的长度是路径上的边或弧的数目
第一个顶点到最后一个顶点相同的路径称为回路或环(cycle)。序列中顶点不重复出现的路径称为简单路径。除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路,称为简单回路或简单环。

在无向图G中,如果从顶点v到顶点v’有路径,则称v和v’是连通的。如果对于图中任意两个顶点vi,vj∈V,vi和vj都是连通的,则称G是连通图(connected graph)
无向图中的极大连通子图称为连通分量。
在有向图G中,如果对于每一对vi,vj∈V,vi≠vj,从vi到vj和从vj到vi都存在路径,则称G是强连通图。有向图中的极大强连通子图称做有向图的强连通分量
如果一个有向图不是强连通的,但是它的基础图,即其弧上去掉方向所形成的图是连通的,则该有向图称为弱连通图。
完全图(complete graph)是其每一对顶点间都存在一条边的图。
一个连通图的生成树是一个极小的连通子图,它含有图中全部的n个顶点,但只有足以构成一棵树的n-1条边。
如果一个有向图恰有一个顶点的入度为0,其余顶点的入度均为1,则有一棵有向树。

图的常见操作有:
(1)按照顶点集V和边弧集VR来创建一个图;
(2)销毁已创建的图;
(3)查找给定值在图中的哪个顶点;
(4)返回图中指定顶点的值;
(5)将图中指定顶点的值设置为给定值;
(6)返回图中指定顶点的邻接顶点;
(7)返回顶点v相对于顶点w的下一个邻接顶点;
(8)在图中添加新的顶点;
(9)删除图中的指定顶点及该顶点相关的弧;
(10)在图中添加弧
(11)在图中删除弧
(12)对图进行深度优先遍历,在遍历过程中对每个顶点调用;
(13)对图进行广度优先遍历,在遍历过程中对每个顶点调用。

在图中,顶点不分大小、主次,所以用一个一维数组来存储是不错的选择。另可以用一个二维数组(称为邻接矩阵)来存储图中的边或弧的信息。也可以用数组与链表的组合(称为邻接表)来存储图中的边或弧。
若图是稠密的,即图中边的个数与顶点个数的平方成正比,邻接矩阵是合适的表示方法。不过在大部分应用中,情况并非如此。

从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这一过程就叫做图的遍历(traverse)。
深度优先遍历(简称DFS),类似于树的前序遍历
广度优先遍历(简称BFS),类似于树的层序遍历
对于图的深度优先遍历与广度优先遍历算法,其在时间复杂度上是一样的。深度优先更适合目标比较明确,以找到目标为主要目的的情况,而广度优先更适合在不断扩大遍历范围时找到相对最优解的情况

求解无向图的连通分量需要使用洪水填充(FloodFill)算法。算法通过给图中的顶点染色,最终使得同一个连通分量的顶点颜色相同,不同连通分量的顶点颜色不同。其算法流程为:
(1)找到一个没有染色的顶点,将其染为新的颜色Color.new,如果没有则算法结束。
(2)初始化一个空队列,并将步骤(1)的顶点插入队列。
(3)不断获得队首元素的值并弹出,将和队首元素相邻的未染色顶点染为Color.new,并将其加入队列。
(4)重复步骤(1),直到所有顶点都被染色。
FloodFill的时间复杂度为O(V+E),其中广度优先遍历的部分可以替换成深度优先遍历,复杂度是一样的。但考虑到递归调用的时间开销,往往广度优先遍历的效率要高一些。

构造连通网的最小代价生成树称为最小生成树(minimum cost spanning tree)。找连通网的最小生成树,有2种经典算法,Prim算法和Kruskal算法。
Prim算法是走一步看一步的思维方式,逐步生成最小生成树。
Prim算法的处理流程为:首先定义带权图G的顶点集合为V,接着定义最小生成树的顶点集合为U,初始集合U为空,接着进行以下操作:
(1)任选一个顶点x,加入集合U,并记录每个顶点到当前最小生成树的最短距离。
(2)选择一个距离当前最小生成树最近的,且不属于集合U的顶点v(如果有多个顶点v,任选其一即可),将顶点v加入集合U,并更新所有与顶点v相连的顶点到当前最小生成树的最短距离。
(3)重复步骤(2),直至集合U等于集合V。
最小生成树构造完毕,集合U记录了最小生成树的所有边。
Prim算法的思想类似贪心策略,每次都会选择一条与当前最小生成树相连且边权值最小的点。Prim算法的时间复杂度为O(V^2),如果加上堆优化,可以把时间复杂度降到O(V*logV+E)。

而Kruskal算法则更有全局意识,直接从图中最短权值的边入手,找寻最后的答案。
Kruskal算法的处理流程为:首先定义带权图G的边集合为E,接着定义最小生成树的边集合为T,初始集合T为空,接着进行以下操作:
(1)把图G看成一个有n棵树的森林,图中每个顶点对应一棵树;
(2)将边集合E的每条边按权值从小到大进行排序;
(3)依次遍历每条边e=(u,v),记顶点u所在树为Tu,顶点v所在树为Tv,如果Tu和Tv不是同一棵树,则将边e加入集合T,并将两棵树Tu和Tv进行合并。
最小生成树构造完毕,集合T记录了最小生成树的所有边。
Kruskal算法也采用了贪心策略,每次都会选择一条两个顶点不在同一棵树且权值最小的边加入集合。Kruskal算法的时间复杂度为O(E*logE)。

Kruskal算法主要是针对边来展开,边数少时效率会非常高,所以对于稀疏图有很大的优势;而Prim算法对于稠密图,即边数非常多的情况会更好一些

对于网图来说,最短路径是指两顶点之间经过的边上权值之和最少的路径,同时称路径上的第一个顶点是源点,最后一个顶点是终点。
Dijkstra算法是常见的求解单源最短问题的算法。
Dijkstra算法的处理流程为:定义带权图G所有顶点的集合为V,接着定义已确定最短路径的顶点集合为U,初始集合U为空。接着进行以下操作:
(1)首先将起点x加入集合U,并在数组A中记录起点x到各个点的最短路径(如果顶点到起点x有直接相连的边,则最短路径为边权值,否则为一个极大值)。
(2)从数组A中选择一个距离起点x最近的,且不属于集合U的顶点v(如果有多个顶点,任选其一即可),将顶点加入集合U,并更新所有与顶点v相连的顶点到起点x的最短路径。
(3)重复步骤(2),直至集合U等于集合V。
算法结束,数组A记录了起点x到其余n-1个点的最短路径。
Dijkstra算法的时间复杂度为O(V^2+E),如果利用堆优化,可将时间复杂度优化为O(VlogV+E),这是最坏情况下最优的单源最短路径算法。
如果图的边上具有负权值,则dijkstra算法是行不通的。

在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,称为AOV网(activity on vertex network)。
设G=(V,E)是一个具有n个顶点的有向图,V中的顶点序列v1,v2,…,vn,满足若从顶点vi到vj有一条路径,则在顶点序列中顶点vi必须在顶点vj之前。则称这样的顶点序列为一个拓扑序列。
所谓拓扑排序,其实就是对一个有向图构造拓扑序列的过程。一个不存在回路的AOV网,我们可以将它应用在各种各样的工程或项目的流程图中,满足各种应用场景的需要

拓扑排序主要是为解决一个工程能否顺序进行的问题,但有时我们还需要解决工程完成需要的最短时间问题。如果要对一个流程图获得最短时间,就必须要分析它们的拓扑关系,并且找到当中最关键的流程,这个流程的时间就是最短时间。
在一个表示工程的带权有向图中,用顶点表示事件,用有向边表示活动,用边上的权值表示活动的持续时间,这种有向图的边表示活动的网,称之为AOE网(activity on edge network)。
尽管AOE网与AOV网都是用来对工程建模的,但它们还是有很大的不同,主要体现在AOV网是顶点表示活动的网,它只描述活动之间的制约关系,而AOE网是用边表示活动的网,边上的权值表示活动持续的时间。因此,AOE网是要建立在活动之间制约关系没有矛盾的基础之上,再来分析完成整个工程至少需要多少时间,或者为缩短完成工程所需的时间,应当加快哪些活动等问题。
一般把路径上各个活动所持续的时间之和称为路径长度,从源点到汇点具有最大长度的路径叫关键路径,在关键路径上的活动叫关键活动。

二、Boost Graph Library

STL中没有图的实现,但在boost中有,为Boost Graph Library (BGL) 。BGL是一个仅有头文件的库,因此以后在应用程序代码中使用该库时,需要在源代码中包含相关的头文件。但是 BGL 需要这个序列化库来进行链接 。
BGL分成数据结构和算法两个部分:图结构和图算法,其中图结构相当于STL中的容器,包含邻接表(adjacency_list)、邻接矩阵(adjacency_matrix)和CSR图(compressed_sparse_row_graph)三种。图算法相当于STL中的算法,不同的图结构对应不同的图算法适用范围。图结构根据它的结构特点被分为“可变图”、“关联图”、“双向图”、“邻接图”、“点表图”、“边表图”、“属性图”、“可变属性图”几个概念。一种图结构可能支持其中的一部分概念而不支持其他的概念,于是就决定了这种图结构所支持的图算法。

在BGL中,图除了可以用邻接矩阵和邻接表表示外,还可以使用边列表来表示。边列表表示简单的说就是一系列边,其中每条边都表示一对顶点的ID,其总共所需内存为O(E)。其边插入的时间复杂度为O(1),但访问特定边的时间复杂度为O(E)(效率不高)。其通过edge_list适配器类来实现。

在BGL中的图算法包括:
(1)图搜索算法;
(2)最小生成树算法;
(3)最短路径算法;
(4)网络流算法:将每条有向边想象成传输物质的管道。每个管道都有一个固定的容量,可以看作是物质能流经该管道的最大速度(譬如可以想象为水流和河槽)。顶点是管道间的连接点,除了源点S,Source)和汇点(T,Target)以外,物质只流经这些顶点。而不聚集在顶点中。网络流中的最大流研究的问题是:在不违背容量限制的条件下,把物质从源点传输到汇点的最大速率是多少。网络流算法要基于三种思想:残留网络(Residual Network),增广路径(Augmenting Path)和割(Cut)。
(5)最小割算法:对于无向图,给定无向图G=(V,E),G的割是将顶点分成两个非空集X和X▔=V-X。如果图是无权的,则割的权值定义为集合X和X▔之间的边个数;如果图是有权的(每条边都有关联的非负权值),则割的权值定义为集合X和X▔之间所有边的权值之和。当图G的割的权值最小时(即没有权值更小的割时),则称该割为最小割。一个图有时会有多个最小割,所有的最小割的权值都相等。最小割算法会确定其中一个割以及最小割的权重。对于有向图,给定有向图G=(V,E),G的割是将顶点分成两个非空集S和T,其中S为源点(source vertex)集,T为汇点(sink vertex)集。如果图是无权的,图割C=(S,T)的容量是从S中一个顶点到T中一个顶点的边的个数,如果图是有权的,则图割容量是从S中一个顶点到T中一个顶点的边的权值的总和。当图G的割C=(S,T)的容量值最小时,则称该割为最小割。

图的抽象数学性质与它们用来解决的具体问题之间的主要联系是附加到图的顶点和边的属性,如距离、容量、权重、颜色等。
BGL没有为无向图提供一个单独的接口,这是因为有向图上的许多算法也适用于无向图。当使用无向图时,只需忽略函数名中的方向性即可。
BGL中提供了IncidenceGraph的概念,其可有效访问图中每个顶点的出边。对于有向图和无向图的出边操作,返回结果是相同的,需要使用者自己忽略掉无向图边的方向性。
BGL中提供了BidirectionalGraph的概念,其在IncidenceGraph的基础上添加了访问入边的方法。对于无向图,BidirectionalGraph的概念是没有意义的。
BGL中提供了AdjacencyGraph的概念,其可有效访问图中的每个顶点。其与IncidenceGraph的概念很类似,IncidenceGraph实际上涵盖了AdjacencyGraph的全部功能。其在访问顶点时比IncidenceGraph要方便,应用于只关注于图中顶点的情况。
BGL中提供了VertexListGraph的概念,其是在IncidenceGraph的基础上,提供了对图中所有顶点进行有效遍历的功能。
BGL中提供了EdgeListGraph的概念,其是在IncidenceGraph的基础上,增加了对图中所有边进行有效访问的功能。
BGL中提供了VertexAndEdgeListGraph的概念,其是对VertexListGraph和EdgeListGraph的细化,没有添加新的功能。其模型基础是邻接表。
BGL中提供了AdjacencyMatrix的概念,其在给定了要访问的原点和目标点的情况下,增加了对图中任意边进行有效访问的功能。在Boost的已有图算法库中,没有使用该概念。其模型基础是邻接矩阵。
BGL中提供了MutableGraph的概念,其在图的基础上,可通过添加或删除边和顶点来对已有图进行修改。其模型基础是邻接表。
BGL中提供了PropertyGraph的概念,其在图的基础上,为每个边和顶点都添加了相关属性。其提供了返回属性映射对象的功能。其模型基础是邻接表。
BGL中提供了MutablePropertyGraph的概念,其是为每个边和顶点都添加了相关属性的MutableGraph。当添加顶点和边时,可指定该顶点或边的属性值。其模型基础是邻接表。

adjacency_list类实现了一个广义邻接表的图结构。其可通过Directed参数来控制创建的是有向图还是无向图。如颜色、距离、权值和用户定义的属性等可以使用类的属性功能附加到图的顶点和边上。这些属性值可以通过图提供的属性映射来访问。
其模板类定义为:
adjacency_list
其成员函数包括:
(1)adjacency_list(),创建一空的图对象或使用给定属性值创建一图对象;
(2)operator=(),复制构造函数;
(3)clear(),从图中移除所有边和顶点;
(4)swap(),交换两个图的边和顶点的属性值。
(5)vertices(),返回可获取图的顶点集合的迭代器;
(6)edges(),返回可获取图的边集合的迭代器;
(7)adjacent_vertices(),返回可获取图中指定顶点的邻接顶点的迭代器,即邻接的弧尾的集合;
(8)inv_adjacent_vertices(),返回可获取图中邻接顶点包含指定顶点的顶点集合的迭代器,即邻接的弧头的集合;
(9)out_edges(),返回可获取图中指定顶点出边的迭代器,对于无向图则返回指定顶点的所有边;
(10)in_edges(),返回可获取图中指定顶点入边的迭代器,其只有在图的Directed参数被设置为bidirectionalS时有效;
(11)source(),返回图中指定边的源点;
(12)target(),返回图中指定边的汇点;
(13)out_degree(),返回图中指定顶点的出度;
(14)in_degree(),返回图中指定顶点的入度,其只有在图的Directed参数被设置为bidirectionalS时有效;
(15)num_vertices(),返回图中顶点的个数;
(16)num_edges(),返回图中边的个数;
(17)vertex(),返回图中的第n个顶点;
(18)edge(),根据指定的两个顶点,如果存在返回以这两个顶点为两端的边和true,否则返回false;
(19)edge_range(),根据指定的两个顶点,返回与该边的平行边的迭代器,其只在允许平行边,以及图的邻接表是按出边排序的集合时可用;
(20)add_edge(),根据指定的两个顶点向图中添加边,并返回该新边的描述器;
(21)remove_edge(),根据指定的两个顶点从图中删除边;
(22)remove_out_edge_if(),从图中移除指定顶点的所有满足条件的出边;
(23)remove_in_edge_if(),从图中移除指定顶点的所有满足条件的入边;
(24)remove_edge_if(),从图中移除所有满足条件的边;
(25)add_vertex(),向图中添加顶点,并返回该新顶点的描述器;
(26)clear_vertex(),从图中移除所有与指定顶点相连的边(包括出边和入边),并保留该顶点;
(27)clear_out_edges(),从图中移除指定顶点的所有出边;
(28)clear_in_edges(),从图中移除指定顶点的所有入边;
(29)remove_vertex(),从图的顶点集合中移除指定顶点,此时要求该顶点的边都已经被删除。

directed_graph类模板是BGL的邻接表的简化版本。提供该类是为了便于使用,但它的性能可能不如自定义的邻接表类。此模板可实现BidirectionalGraph, VertexIndexGraph, EdgeIndexGraph概念。
其模板类定义为:
directed_graph
undirected_graph类模板是BGL的邻接表的简化版本。提供该类是为了便于使用,但它的性能可能不如自定义的邻接表类。此模板可实现BidirectionalGraph, VertexIndexGraph, EdgeIndexGraph概念。
其模板类定义为:
undirected_graph

adjacency_matrix类使用传统的邻接矩阵形式实现了BGL的图接口。对于有V个顶点的图,则使用一V*V的矩阵,每个元素使用bool值来表示是否有边
其模板类定义为:
adjacency_matrix
其成员函数包括:
(1)adjacency_matrix(),使用指定的顶点个数来创建一个图;
(2)vertices(),返回可获取图的顶点集合的迭代器;
(3)edges(),返回可获取图的边集合的迭代器;
(4)adjacent_vertices(),返回可获取图中指定顶点的邻接顶点的迭代器;
(5)out_edges(),返回可获取图中指定顶点出边的迭代器,对于无向图则返回指定顶点的所有边;
(6)source(),返回图中指定边的源点;
(7)target(),返回图中指定边的汇点;
(8)out_degree(),返回图中指定顶点的出度;
(9)in_edges(),返回可获取图中指定顶点入边的迭代器,其只有在图的Directed参数被设置为bidirectionalS时有效;
(10)in_degree(),返回图中指定顶点的入度,其只有在图的Directed参数被设置为bidirectionalS时有效;
(11)num_vertices(),返回图中顶点的个数;
(12)num_edges(),返回图中边的个数;
(13)vertex(),返回图中的第n个顶点;
(14)edge(),根据指定的两个顶点,如果存在返回以这两个顶点为两端的边和true,否则返回false;
(15)add_edge(),根据指定的两个顶点向图中添加边,并返回该新边的描述器;
(16)remove_edge(),根据指定的两个顶点从图中删除边;
(17)clear_vertex(),从图中移除所有与指定顶点相连的边(包括出边和入边),并保留该顶点;

compressed_sparse_row_graph类是一使用压缩稀疏行(CSR)格式存储的有向(双向)图的类模板。虽然CSR图的开销比其他图实现(例如邻接表)小得多,但它不提供任何可变性,即不能从CSR图中添加或删除顶点或边。其应用在高性能应用程序或不需要更改的非常大的图中
CSR格式将顶点和边保存在不同的数组中,这些数组的索引分别对应于顶点或边的标识符。边数组是按照每个边的源点进行排序的,其只包含边的汇点。顶点数组储存到边数组的偏移量,提供从每个顶点流出的第一条边的偏移量。图中第i个顶点的出边迭代是通过访问edge_array[vertex_array[i]],edge_array[vertex_array[i]+1],…,edge_array[vertex_array[i+1]]来实现的。这种数据结构的内存使用为O(V+E)。模板参数Directed控制边是有向的还是无向的,有向CSR图的Directed = directedS,双向CSR图的Directed = bidirectionalS。
此模板可实现Graph,IncidenceGraph,AdjacencyGraph,VertexListGraph,EdgeListGraph,PropertyGraph概念。
其模板类定义为:
templateclass compressed_sparse_row_graph
其成员函数包括:
(1)compressed_sparse_row_graph(),图构造器;
(2)assign(),清理现有CSR图,并使用给定属性构造新的CSR图;
(3)VertexProperty& operator[],检索指定顶点的属性值;
(4)EdgeProperty& operator[],检索指定边的属性值;
(5)vertex(),返回图中的第n个顶点;
(6)edge(),根据指定的两个顶点,如果存在返回以这两个顶点为两端的边和true,否则返回false;
(7)edge_from_index(),返回图中的第n条边;
(8)add_edge(),根据指定的两个顶点向图中添加边;
(9)add_edges_sorted(),向图中添加一系列边;

subgraph类提供一种跟踪图和其子图的机制。subgraph类实现派生子图。主图及其子图以树型数据结构维护。主图是根,子图要么是根的子图,要么是其他子图的子图。这个树中的所有节点,包括根图,都是子图类的实例。确保子图中每个子图的实现都是一个子图。subgraph类实现了BGL的图接口,因此每个子图对象都可以被视为一个图。
此模板可实现VertexListGraph,EdgeListGraph,VertexMutableGraph,BidirectionalGraph概念。
其模板类定义为:
subgraph
其成员函数包括:
(1)subgraph(),使用n个顶点和0条边来创建根图对象;
(2)vertex_descriptor local_to_global(),转换一局部顶点描述符为对应的全局顶点描述符;
(3)vertex_descriptor global_to_local(),转换一全局顶点描述符为对应的局部顶点描述符;
(4)edge_descriptor local_to_global(),转换一局部边描述符为对应的全局边描述符;
(5)edge_descriptor global_to_local(),转换一全局边描述符为对应的局部边描述符;
(6)find_vertex(),如果指定顶点在子图中,则返回对应的局部顶点描述符合true,否则返回false;
(7)root(),返回子图树的根图;
(8)is_root(),如果图是子图树的根,则返回true,否则返回false;
(9)parent(),返回父图;
(10)children(),返回获取孩子子图的迭代器;
(11)vertices(),返回获取子图顶点集的迭代器对;
(12)edges(),返回获取子图边集的迭代器对;
(13)adjacent_vertices(),返回子图中邻接到指定顶点的顶点们的迭代器对;
(14)out_edges(),返回子图中指定顶点的出边的迭代器对;
(15)in_edges(),返回子图中指定顶点的入边的迭代器对;
(16)source(),返回子图中指定边的源点;
(17)target(),返回子图中指定边的汇点;
(18)out_degree(),返回子图中指定顶点的出度;
(19)in_degree(),返回子图中指定顶点的入度;
(20)num_vertices(),返回子图中顶点的个数;
(21)num_edges(),返回子图中边的个数;
(22)vertex(),返回子图中的第n个顶点;
(23)edge(),根据指定的两个顶点,如果存在返回以这两个顶点为两端的边;
(24)add_edge(),根据指定的两个顶点向子图中添加边;
(25)remove_edge(),根据指定的两个顶点从子图中删除边;
(26)add_vertex(),将顶点添加到子图中,并返回新顶点的描述符;

edge_list类将一对边迭代器转换为EdgeListGraph的模型实现。
其模板类定义为:
edge_list
其成员函数包括:
(1)edge_list(),使用边迭代器来创建图对象;
(2)edges(),返回获取图边集的迭代器对;
(3)source(),返回子图中指定边的源点;
(4)target(),返回子图中指定边的汇点;

reverse_graph适配器通过翻转图的入边和出边,从而实现图的转换。该反向图的构造时间复杂度是常数时间。此模板可实现BidirectionalGraph,VertexListGraph,PropertyGraph概念。
其模板类定义为:
reverse_graph
其成员函数包括:
(1)reverse_graph(),根据已知图来创建反向视图;
(2)make_reverse_graph(),创建反向图的帮助函数;
(3)vertices(),返回获取图顶点集的迭代器对;
(4)out_edges(),返回图中指定顶点的出边的迭代器对;
(5)in_edges(),返回图中指定顶点的入边的迭代器对;
(6)adjacent_vertices(),返回图中指定顶点的邻接顶点集合的迭代器对;
(7)source(),返回图中指定边的源点;
(8)target(),返回图中指定边的汇点;
(9)out_degree(),返回图中指定顶点的出度;
(10)in_degree(),返回图中指定顶点的入度;
(11)num_vertices(),返回图中顶点的个数;
(12)vertex(),返回图中的第n个顶点;
(13)edge(),根据指定的两个顶点,如果存在返回以这两个顶点为两端的边;

filtered_graph类模板可创建图的过滤图。其通过条件确定原始图的哪些边和顶点在过滤后的图中显示。过滤图并不创建新的图副本,而是使用原图的引用。过滤图不改变原图的结构,但通过过滤图的属性映射可以改变原图的顶点和边属性。此模板可实现VertexAndEdgeListGraph,PropertyGraph概念。
其模板类定义为:
filtered_graph
其成员函数包括:
(1)filtered_graph(),基于指定的边和顶点创建图的过滤图;
(2)operator=,复制构造函数;
(3)vertices(),返回获取图顶点集的迭代器对;
(4)edges(),返回获取图边集的迭代器对;
(5)adjacent_vertices(),返回图中指定顶点的邻接顶点集合的迭代器对;
(6)out_edges(),返回图中指定顶点的出边的迭代器对;
(7)in_edges(),返回图中指定顶点的入边的迭代器对;
(8)source(),返回图中指定边的源点;
(9)target(),返回图中指定边的汇点;
(10)out_degree(),返回图中指定顶点的出度;
(11)in_degree(),返回图中指定顶点的入度;
(12)num_vertices(),返回底层图中顶点的个数;
(13)num_edges(),返回底层图中边的个数;
(14)edge(),根据指定的两个顶点,如果存在返回以这两个顶点为两端的边;
(15)edge_range(),返回与指定顶点对平行的所有边的出边迭代器;

grid_graph表示多维的具有用户定义的维度和环绕的矩形顶点网格。此模板可实现IncidenceGraph,AdjacencyGraph,VertexListGraph,EdgeListGraph,BidirectionalGraph概念。

许多的图算法函数有很长的参数列表,其中大多数都有默认值,这导致以下问题:C++没有提供处理模板函数的默认参数的机制,但可以通过创建具有不同数量参数的算法的乘法版本来解决。但该解决方案不能让人满意,为此使用bgl_named_params类来解决。其允许用户提供任意顺序的参数,并根据参数名称将参数与形参匹配。通常用户不需要直接使用bgl_named_params类,因为boost有weight_map等函数,可自动创建bgl_named_params实例。

算法1:基础操作。
(1)void copy_graph(const VertexListGraph& G, MutableGraph& G_copy, const bgl_named_params& params = all defaults),复制图,该函数用于将图中的所有顶点和边复制到新图中。此外还可复制图的顶点和边属性。时间复杂度为O(V+E)。
(2)void transpose_graph(const VertexListGraph& G, MutableGraph& G_T, const bgl_named_params& params = all defaults),转换图,该函数用于计算有向图的转置。图的转置是原图所有边方向翻转后的图。时间复杂度为O(V+E)。

算法2:核心搜索
(1)void breadth_first_search(Graph& G, typename graph_traits::vertex_descriptor s, const bgl_named_params& params),广度优先搜索,其对有向或无向图进行广度优先搜索。其可用于计算从源点到所有可达顶点的最短路径和该距离。时间复杂度为O(V+E)。
(2)void breadth_first_visit(IncidenceGraph& G, typename graph_traits::vertex_descriptor s, const bgl_named_params& params),广度优先访问,其与广度优先搜索基本相同,只是算法中没有初始化颜色标记。用户需要在调用函数前确保每个顶点的颜色是白色。该函数可用于IncidenceGraph,而不仅仅是VertexListGraph。时间复杂度为O(E)。
(3)void depth_first_search(Graph& G, const bgl_named_params& params),深度优先搜索,其对有向图进行深度优先遍历。深度优先搜索对于分类图中的边以及对顶点施加排序非常有用。时间复杂度为O(V+E)。
(4)void depth_first_visit(IncidenceGraph& g, typename graph_traits::vertex_descriptor s, DFSVisitor& vis, ColorMap color),深度优先访问,其使用深度优先模式来访问与源点s相同连接成分中的所有顶点。其主要用于实现深度优先搜索。时间复杂度为O(E)。
(5)void undirected_dfs(Graph& G, const bgl_named_params& params),无向深度优先搜索,其对无向图进行深度优先搜索。时间复杂度为O(V+E)。

算法3:其他核心算法。
(1)void topological_sort(VertexListGraph& g, OutputIterator result, const bgl_named_params& params = all defaults),拓扑排序,其创建顶点的线性排序,以便如果边(u,v)在图中,则v排序于u前面。该算法只能用于无向图,其实现包括深度优先搜索的调用。时间复杂度为O(V+E)。
(2)void transitive_closure(const Graph& g, GraphTC& tc, const bgl_named_params& params = all defaults),闭包传递,图G=(V,E)的闭包传递为G*=(V,E*),E为只有当从顶点u到v有路径时才添加的边集合。其将输入的图转换为图的闭包传递。时间复杂度为O(|V||E|)。
(3)void lengauer_tarjan_dominator_tree(const Graph& g, const typename graph_traits::vertex_descriptor& entry, DomTreePredMap domTreePredMap),lengauer-tarjan支配树,其为有向图建立支配树。支配的定义为:如果有向图从入口到顶点v必须经过顶点u,则称u支配v。本函数实现了计算相对容易的半支配,及路径压缩2种优化方法,时间复杂度为O((V+E)*log(V+E))。

算法4:最短路径/最小代价算法
(1)void dijkstra_shortest_paths(Graph& g, typename graph_traits::vertex_descriptor s, const bgl_named_params& params),dijkstra最短路径,该函数解决了所有边权非负的情况下加权有向图或无向图上的单源最短路径问题。当某些边缘权重为负时,使用Bellman-Ford算法。当所有边缘权值都等于1时,使用宽度优先搜索代替Dijkstra算法。该算法使用颜色标记(白色、灰色和黑色)来跟踪每个顶点所在的集合。黑色的顶点在S中。白色或灰色的顶点在V-S中。白色顶点尚未发现,灰色顶点在优先队列中。时间复杂度为O(VlogV+E)。
(2)void dijkstra_shortest_paths_no_color_map(const Graph& graph, typename graph_traits::vertex_descriptor start_vertex, const bgl_named_params& params),dijkstra无颜色映射最短路径,该函数基本与dijkstra_shortest_paths()相同,不同是其不使用颜色映射来识别已发现或未发现的顶点,而是通过距离映射来实现的,因此,如果边具有无限权值,则该函数无法正常运行。时间复杂度为O(VlogV+E)。
(3)bool bellman_ford_shortest_paths(const EdgeListGraph& g, Size N, const bgl_named_params& params = all defaults),bellman-ford最短路径,该算法可解决具有正负边权值图的单源最短路径问题。在调用该函数之前,用户必须将源顶点的距离指定为零,并将所有其他顶点的距离指定为无穷远。时间复杂度为O(VE)。
(4)void dag_shortest_paths(const VertexListGraph& g, typename graph_traits::vertex_descriptor s, const bgl_named_params& params),DAG最短路径该函数可解决加权有向无环图(DAG)上的单源最短路径问题,其比dijkstra算法和bellman-ford算法效率更高。当所有边缘权值都等于1时,使用宽度优先搜索代替此算法。时间复杂度为O(V+E)。
(5)bool johnson_all_pairs_shortest_paths(VertexAndEdgeListGraph& g1, DistanceMatrix& D, VertexID id1, Weight w1, const BinaryPredicate& compare, const BinaryFunction& combine, const Infinity& inf, DistanceZero zero),该函数寻找图中每对顶点间的最短距离。如果图中存在负权值环,则函数返回false。每对顶点之间的距离存储在距离矩阵中,其花费时间较长,时间复杂度为O(V
ElogV)。
该算法主要用于计算稀疏图,对于稠密图,可使用floyd_warshall_all_pairs_shortest_paths()
(6)bool floyd_warshall_initialized_all_pairs_shortest_paths(const VertexListGraph& g, DistanceMatrix& d, const bgl_named_params& params),该函数寻找图中每对顶点间的最短距离。如果图中存在负权值环,则函数返回false。每对顶点之间的距离存储在距离矩阵中。该算法主要用于计算稠密图,对于稀疏图,可使用johnson_all_pairs_shortest_paths()。时间复杂度为O(V^3)。
(7)void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, const EdgeIndexMap& edge_index_map, typename graph_traits::vertex_descriptor s, typename graph_traits::vertex_descriptor t, std::vector >& pareto_optimal_solutions, std::vector& pareto_optimal_resource_containers, const Resource_Container& rc, const Resource_Extension_Function& ref, const Dominance_Function& dominance, Label_Allocator la, Visitor vis),资源约束最短路径,该函数用于在具有任意弧长的有向图中,在满足
资源约束的条件下,寻找从任意源点到终点的最短路径。资源约束可能为:
①总行程时间不得超过某个上限;
②在所经过路径的顶点处所捡取的货物总量要小于等于某个容量限制;
③如果在路径上访问了i和j两个顶点,则该路径访问这两个顶点的顺序必须是先访问i后访问j等。
这个问题是强意义上的NP-hard问题。如果路径不必是初等的,即允许顶点多次访问,则问题可以在伪多项式时间内求解。其关键问题是,SPPRC中的两条(部分)路径是不可比较的,这使得SPPRC类似于一个多准则决策问题。该算法的时间复杂度取决于具体问题,对于具有负环的图,其时间复杂度随顶点和边的数量呈指数上升。
(8)void astar_search(const VertexListGraph &g, typename graph_traits::vertex_descriptor s, AStarHeuristic h, const bgl_named_params& params),A
搜索,该算法对具有非负加权的有向和无向图进行启发式搜索。A搜索由一个启发式函数引导。启发函数h(v)是一个估计从图中的非目标状态(v)到某个目标状态(g)的代价的函数。直观上说,A走到目标的路径是由启发式函数估计出的最佳路径。与最佳优先搜索不同,A考虑了从搜索开始到v的已知成本;A采用的路径由函数f(v)=g(v)+h(v)引导,其中h(v)是启发式函数,g(v)是从开始到v的已知成本,A的效率高度依赖于它所使用的启发函数。A算法与dijkstra最短路径算法非常相似。其通过创建一个搜索树来寻找从源点到每个其他顶点的所有最短路径,根据到达某个目标的剩余成本来检查这个顶点,是一个启发函数估计的。通常使用A来查找图中的某个或多个特定目标顶点,然后终止搜索。A算法对于搜索隐式图特别有用。隐式图是在搜索开始时不完全已知的图。在访问一个顶点时,它的邻居被“生成”并添加到搜索中。
隐式图对于搜索大的状态空间特别有用,例如在博弈场景(例如国际象棋)中,在这种情况下可能无法存储整个图。隐式搜索可以通过创建生成新扩展顶点的邻居的特殊访问者来执行。与其他方法相比,A*算法的一个主要优点是它避免了状态空间中的“循环”,搜索不会被图中的循环困住。时间复杂度为O((E+V)*logV)。

算法5:最小生成树算法
(1)OutputIterator kruskal_minimum_spanning_tree(Graph& g, OutputIterator tree_edges, const bgl_named_params& params = all defaults),kruskal算法,该函数在有权无向图上生成最小生成树。最小生成树是连接图中所有顶点的一组边,其所生成的树的边的总权值最小。该函数在生成最小生成树的过程中使用了按秩合并和路径压缩两种优化操作。时间复杂度为O(ElogE)。
(2)void prim_minimum_spanning_tree(const Graph& g, PredMap p_map, const bgl_named_params& params),prim算法,该函数用于求解有权无向图的最小生成树。时间复杂度为O(E
logV)。其相比于Kruskal算法,更适合用于稠密图。

算法6:随机生成树算法。
(1)void random_spanning_tree(Graph& G, Gen& gen, const bgl_named_params& params),随机生成树,其使用wilson算法基于循环消除随机游走,在有向和无向图上生成随机生成树。该函数实现了有权和无权两个版本。在无权版本中,所有生成树的可能性相等。在有权版本中,特定生成树的概率是其边权值的乘积。

算法7:两个图的通用生成树算法(MRT)。
(1)void two_graphs_common_spanning_trees(const Graph& iG, Order iG_map, const Graph& vG, Order vG_map, Func func, Seq inL),MRT算法(基于minty,read,tarjan的学术论文)是用于通用生成树问题的有效算法。该算法是电路分析的基础,在电子学有着广泛的应用。其另一个应用领域是网络。通用生成树问题可描述为:如果有两个用边链表表示的图,其通用生成树是一组索引,用于标识两个图中各自的生成树。尽管用图的边链表很容易实现,但用邻接表则很难实现,这是因为需要绝对索引来表示边。注意,通用生成树既是第一个图生成树的子集,也是第二个图生成树的子集。

算法8:连接成分算法
(1)value_type connected_components(VertexListGraph& G, ComponentMap comp, const bgl_named_params& params = all defaults),连接成分算法,其使用基于深度优先搜索的方法计算无向图的连接成分。无向图的连接成分是一组彼此都能到达的顶点集合。如果在图增长的过程中需要维护连接成分,则使用基于并查集的incremental_components()函数会更快。而对于静态图,本函数更快。时间复杂度为O(V+E)。
(2)value_type strong_components(Graph& g, ComponentMap comp, const bgl_named_params& params = all defaults),强连通成分算法,其使用基于深度优先搜索的tarjan算法来计算有向图的强连通成分。时间复杂度为O(V+E)。
(3)biconnected_components(const Graph& g, ComponentMap comp, OutputIterator out, const bgl_named_params& params),双向连接成分算法;
OutputIterator articulation_points(const Graph& g, OutputIterator out, const bgl_named_params& params),连接点算法。
如果移除任何一个顶点(以及该顶点上的所有边)都不能断开连通图,则该连通图是双连通的。更一般的,图的双连通成分是顶点的最大子集,以使从一个特定的成分中删除一个顶点都不会使该成分断开。与连通成分不同,顶点可能属于多个双连通成分:那些属于多个双连通成分的顶点称为连接点,或称为切割顶点。连接点是其删除会增加图中连通成分数量的顶点。因此,没有连接点的图是双连通的。时间复杂度为O(V+E)。
(4)void initialize_incremental_components(VertexListGraph& G, DisjointSets& ds),通过使图中每个顶点成为其自身成分(或集合)的成员,来为增量连通成分算法准备并查集数据结构。
void incremental_components(EdgeListGraph& g, DisjointSets& ds),计算图的连通成分并将结果嵌入并查集数据结构中。
bool same_component(Vertex u, Vertex v, DisjointSet& ds),判断指定的两个顶点是否属于相同的成分。
component_index,该类为图的成分提供类似STL容器的视图。每个成分都是一个容器对象,可通过operator[]进行访问。
增量连通成分算法,其包含一系列函数和类,来共同计算无向图的连通成分,该算法基于并查集。整个处理过程的时间复杂度为O(V+E*alpha(E,V)),alpha是ackermann函数的逆函数,其增长比较缓慢值≤4,即时间复杂度略大于O(V+E)。

算法9:最大流和匹配算法
(1)edmonds_karp_max_flow(Graph& g, typename graph_traits::vertex_descriptor src, typename graph_traits::vertex_descriptor sink, const bgl_named_params& params = all defaults),edmonds-karp最大流算法,该函数计算网络的最大流。该函数还计算边中所有两个顶点间的流量值,以剩余容量的形式返回。该算法要求输入的表示网络的图必须扩充为每条边都有反向边的有向图。
该算法的处理效果不如push_relabel_max_flow()和boykov_kolmogorov_max_flow()。时间复杂度为O(VE^2)。
(2)push_relabel_max_flow(Graph& g, typename graph_traits::vertex_descriptor src, typename graph_traits::vertex_descriptor sink, const bgl_named_params& params = all defaults),goldberg提出的算法,该算法要求输入的表示网络的图必须扩充为每条边都有反向边的有向图。时间复杂度为O(V^3)。
(3)boykov_kolmogorov_max_flow(Graph& g, typename graph_traits::vertex_descriptor src, typename graph_traits::vertex_descriptor sink, const bgl_named_params& params = all defaults),boykov-kolmogorov最大流算法,该函数用于计算网络的最大流。该函数还计算边中所有两个顶点间的流量值,以剩余容量的形式返回。该算法要求输入的表示网络的图必须扩充为每条边都有反向边的有向图。
(4)void edmonds_maximum_cardinality_matching(const Graph& g, MateMap mate),该函数和checked_edmonds_maximum_cardinality_matching()函数都用于在无向图中查找最大基数匹配。该匹配在MateMap中返回,其将一个顶点映射到顶点的属性集。时间复杂度为O(V
Ealpha(V,E)),即略大于O(VE)。
(5)void maximum_weighted_matching(const Graph& g, MateMap mate),最大加权匹配算法,有权图的最大加权匹配是指边的权值之和最大的匹配。该匹配在MateMap中返回,其将一个顶点映射到顶点的属性集。时间复杂度为O(V^3)。

算法10:最小代价最大流算法。
(1)void cycle_canceling(Graph &g, const bgl_named_params & params = all defaults),该函数计算在给定流量下网络的最小代价流。该函数还计算边中所有两个顶点间的流量值,以剩余容量的形式返回。该算法要求输入的表示网络的图必须扩充为每条边都有反向边的有向图。时间复杂度为O(C*|V||E|),其中C是迭代次数的上界。
(2)void successive_shortest_path_nonnegative_weights(Graph &g, typename graph_traits::vertex_descriptor s, typename graph_traits::vertex_descriptor t, const bgl_named_params & params = all defaults),该函数计算网络的最小代价的最大流量。该函数还计算边中所有两个顶点间的流量值,以剩余容量的形式返回。该算法要求输入的表示网络的图必须
扩充为每条边都有反向边的有向图。时间复杂度为O(U
|E|+|V|*log|V|)),其中U是dijkstra算法求解的迭代次数上界。
(3)find_flow_cost(const Graph & g, const bgl_named_params & params = all defaults),该函数计算在给定流量下网络的最小代价流。该函数还计算边中所有两个顶点间的流量值,以剩余容量的形式返回。如果想计算最大流的最小代价,可使用successive_shortest_path_nonnegative_weights()或cycle_canceling()。时间复杂度为O(|E|)。

算法11:最小割算法
(1)stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, const bgl_named_params& params = all defaults),该函数确定连通无向图的最小割和最小割的权值
图的割是将顶点划分为2个非空集合。如果图是无权的,则这种划分的权值是两个集合间边的数目。如果图是有权的,则划分的权值是集合间所有边的权值之和。最小割指的是划分的权值最小。有时一个图有多个最小割,这些割的权值都相等,可使用stoer_wagner_min_cut()函数来确定一个最小割和其权值。时间复杂度为O(VE+V^2logV)。

算法12:稀疏矩阵排序算法。
(1)cuthill_mckee_ordering(const IncidenceGraph& g, typename
graph_traits::vertex_descriptor s, OutputIterator inverse_permutation, ColorMap color, DegreeMap degree),该函数通过重新排序分配给每个顶点的索引来减少图的带宽。该算法的工作原理是局部最小化第i个带宽。除了第一步,相邻的顶点按照递增顺序排列在队列中,基本上都是按照广度优先搜索的顺序来分配的。时间复杂度为O(mlogm|V|),其中m=max{degree(v)|v in V}。
(2)king_ordering(const IncidenceGraph& g, typename graph_traits::vertex_descriptor s, OutputIterator inverse_permutation, ColorMap color, DegreeMap degree, VertexIndexMap index_map),该算法通过重新排列分配给每个顶点的索引来减少图的带宽。该算法的工作原理是局部最小化第i个带宽。除了第一步,相邻的顶点按照递增顺序排列在队列中,基本上都是按照广度优先搜索的顺序来分配的。时间复杂度为O(m^2logm|E|),其中m=max{degree(v)|v in V}。
(3)void minimum_degree_ordering(AdjacencyGraph& G, OutDegreeMap outdegree, InversePermutationMap inverse_perm, PermutationMap perm, SuperNodeSizeMap supernode_size, int delta, VertexIndexMap id),最小度排序算法,其是一种填充规约矩阵排序算法。当使用稀疏形式的Cholesky因式分解(它是对称矩阵的高斯消去的变体)求解方程组(如Ax=b)时,由于消去过程,矩阵中一度为零的元素往往变成非零元素。这就是所谓的“填充”,填充是不好的,因为它使矩阵不那么稀疏,因此在消去的后期阶段和使用结果因式分解的计算中消耗更多的时间和空间。现在发现,矩阵行的重新排序会对填充量产生显著影响。因此,我们可以找到一个很好的解,而不是一个很好的解。最小度排序算法就是这样一种方法。
(4)sloan_ordering(Graph& g, typename graph_traits::vertex_descriptor s, typename graph_traits::vertex_descriptor e, OutputIterator ermutation, ColorMap color, DegreeMap degree, PriorityMap priority, Weight W1, Weight W2),该算法的目的是通过重新排序分配给每个顶点的索引来减少图的轮廓和wavefront。Sloan算法需要一个起始点和一个结束点。但其提供的默认值(weight1/weight2=1/2)大多数情况下都是非常好的。时间复杂度为O(logm
|E|),其中m=max{degree(v)|v in V}。
(5)sloan_start_end_vertices(Graph& G, typename graph_traits::vertex_descriptor &s, ColorMap color, DegreeMap degree),该算法的目的是为sloan_ordering()函数找到良好的起始点和结束点。该算法也基于广度优先搜索。

算法13:图度量算法。
(1)ith_wavefront(typename graph_traits::vertex_descriptor i, const Graph& g),计算第i个顶点的wavefront。
max_wavefront(const Graph& g),计算图的最大wavefront。
aver_wavefront(const Graph& g),计算图的平均wavefront(即所有wavefront的和除以顶点个数)。
rms_wavefront(const Graph& g),计算所有wavefront的均方根。
(2)bandwidth(const Graph& g),图的带宽是两个相邻顶点间的最大距离,用以单位间隔放置顶点的一条线上的测量距离。即如果图G=(V,E)的每个顶点都分配一个索引,则图的带宽为B(G)=max{|index[u]-index[v]| |(u,v) in E}。
(3)ith_bandwidth(typename graph_traits::vertex_descriptor i, const Graph& g),图的第i个带宽是第i个顶点和任何相邻顶点间距离的最大值。因此图的带宽可表示为所有第i个顶点带宽中的最大值,即B(G)=max{Bi(G) | i=0,1,…,|V|-1}。
(4)void brandes_betweenness_centrality(const Graph& g, const bgl_named_params& params),该算法计算图中每个顶点或每条边的中间度。顶点的中间度被定义为sum.(s≠v≠t)[σst(v)/σst],其中σst是从顶点s到顶点t的最短路径数,σst(v)是从顶点s经过顶点v到顶点t的最短路径数。边的中间度与顶点中间度类似,可用来确定最短路径必须经过的边。调用该函数一次可同时计算顶点中间度和边中间度。该算法可用于有权图和无权图,其结果是绝对中间度。对于无权图时间复杂度为O(VE),对于有权图时间复杂度为O(VE+V*(V+E)*logV)。
(5)maximum_cycle_ratio(const Graph &g, VertexIndexMap vim, EdgeWeight1 ewm, EdgeWeight2 ew2m, std::vector *pcc = 0),该函数计算有权有向多重图的最大环比G=(V,E,W1,W2),其中W1和W2是边的权函数。作为多重图,其可以有多条边连接到一对顶点。让每条边e有2个权值W1(e)和W2(e),c为图g的一个环,则环率cr©为:cr©=sum.(e∈c)[W1(e)] / sum.(e∈c)[W2(e)] 。最大(最小)环率是图中所有环的最大(最小)环率值。如果图中无环,则最大环率/最小环率=INF。另有maximum_cycle_mean()和minimum_cycle_mean()函数可计算图的最大/最小环率。该算法没有精确的时间复杂度上界,其绝对时间复杂度为O(|E|)。

算法14:图结构比较算法。
(1)bool isomorphism(const Graph1& g1, const Graph2& g2, const bgl_named_params& params = all defaults),同构是图中一个顶点到另一个顶点间的1:1映射,这样就保留了相邻关系。即同构是一函数,对于图1中所有顶点对a,b,只有当边(f(a),f(b))在图2中,边(a,b)才在图1中。该函数当两个图间存在同构时返回true,否则返回false。时间复杂度为O(|V|!)。
(2)bool vf2_subgraph_iso(const GraphSmall& graph_small, const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback),该函数用于查找大图和小图间的所有引导子图同构,并将它们输出到用户回调函数,它一直持续到用户回调函数返回false或搜索空间被完全探索。时间复杂度为O(V!V)。
(3)void mcgregor_common_subgraphs(const GraphFirst& graph1, const GraphSecond& graph2, SubGraphCallback user_callback, bool only_connected_subgraphs, const bgl_named_params& params),该函数找到两个图间的所有通用子图并将其输出到用户回调函数。该算法基于深度优先搜索。时间复杂度为O(V1
V2)。

算法15:布局算法。
(1)该算法提供了各种拓扑如正方形拓扑、球体拓扑、心形拓扑等,用于为图布局算法生成结果。拓扑是对可执行布局空间的描述。
convex_topology类模板,实现指定维度的任何凸拓扑的基本距离和点位移函数。它本身不是拓扑,而任何凸拓扑的派生基类。
hypercube_topology类模板,实现指定维度的超立方体,是一个凸拓扑。
square_topology类模板,实现二维超立方体拓扑。
cube_topology类模板,实现三维超立方体拓扑。
ball_topology类模板,实现指定维度的球,是一凸拓扑。
circle_topology类模板,实现二维球拓扑。
sphere_topology类模板,实现三维球拓扑。
heart_topology类模板,实现心形拓扑,其是非凸、非平凡拓扑。
(2)void random_graph_layout(const Graph& g, PositionMap position_map, const Topology& space),该算法将图的点放在给定空间内的随机位置。时间复杂度为O(|V|)。
(3)void circle_graph_layout(const VertexListGraph & g, PositionMap position),该函数在正多边形的点上布局图的顶点。
(4)bool kamada_kawai_spring_layout(const Graph & g, PositionMap position, WeightMap weight, const Topology& space, unspecified edge_or_side_length, Done done, typename property_traits< WeightMap >::value_type spring_constant, VertexIndexMap index, DistanceMatrix distance, SpringStrengthMatrix spring_strength, PartialDerivativeMap partial_derivatives),该算法为连通的无向图进行图布局(二维)。它通过将图的布局与一个动态弹簧系统相关联,并将该系统中的能量最小化。
两个顶点之间弹簧的强度与这两个顶点之间最短距离的平方成反比。本质上,在图论意义上更接近的顶点将具有更强的弹簧,因此将放置在更靠近的位置。在调用本函数前,建议先使用circle_layout()函数将顶点放置在正多边形的顶点上。
(5)void fruchterman_reingold_force_directed_layout(const Graph& g, PositionMap position, const Topology& space, const bgl_named_params& params),该算法对无权无向图进行布局。与kamada-kawai布局算法不同,该算法支持不连通图的布局。这是一种力导向算法,也就是说顶点布局是由将顶点拉在一起并将它们推开的力决定的。吸引力只发生在相邻顶点之间,而排斥力则发生在每对顶点之间。每次迭代计算每个顶点上的力之和,然后将顶点移动到它们的新位置。顶点的移动通过迭代系统的温度来减轻:随着算法在连续迭代中的进展,温度应该降低,以便顶点在适当的地方固定下来。冷却时间、吸引力和斥力可由用户提供。在调用本函数前,建议先使用random_graph_layout()函数将顶点随机放置。时间复杂度为O(|V|^2+|E|)。
(6)void gursoy_atun_layout(const VertexListAndIncidenceGraph& g, const Topology& space, PositionMap position, int nsteps = num_vertices(g), double diameter_initial = sqrt((double)num_vertices(g)), double diameter_final = 1, double learning_constant_initial = 0.8, double
learning_constant_final = 0.2, VertexIndexMap vertex_index_map = get(vertex_index, g), EdgeWeightMap weight = dummy_property_map()),该算法对无权和有权有向图进行布局。其与kamada-kawai和fruchterman-reingold算法不同,没有明确地努力以视觉方式布局图,而是试图在拓扑内均匀分布顶点,使顶点接近其相邻的顶点。该算法基于自组织映射。

算法16:聚类算法。
(1)void betweenness_centrality_clustering(MutableGraph &g, Done done, EdgeCentralityMap edge_centrality, VertexIndexMap vertex_index),该算法基于边的中间度进行图聚类。其是一种迭代算法,在每一步计算边的中间度,并去除中间度最大的边。

算法17:平面图算法。
如果一个图可以在二维空间中绘制,并且没有两条边相交,那么它就是平面图。这种平面图的绘制称为平面绘制。每一个平面图也允许绘制直线图,即一个平面图其中每一条边都用一条线段表示。任何平面图都将平面划分为不同的区域,这些区域由图形边作为边界,称为面。
(1)boyer_myrvold_planarity_test(),Boyer-Myrvold平面度测试/嵌入。每个平面图都属于一个等价类,称为平面嵌入,该类由图中每个顶点周围相邻边的顺时针排序来定义。平面嵌入是平面图实际绘制的一种方便的中间表示,许多平面图绘制算法都是将平面嵌入映射到平面图的函数。通常时间复杂度为O(E),如果是稠密图则时间复杂度为O(V+E)。
(2)void planar_face_traversal(const Graph& g, PlanarEmbedding embedding, PlanarFaceVisitor& visitor, EdgeIndexMap em),平面图的面遍历涉及到遍历图的所有面,在每个面上,遍历面的所有顶点和边。通过每个面的所有顶点和边的迭代沿着面边界的一条路径进行。时间复杂度为O(V+E)。
(3)void planar_canonical_ordering(const Graph& g, PlanarEmbedding embedding, OutputIterator ordering, VertexIndexMap vm),平面的正则排序是具有以下性质的最大平面图的顶点序:①图是双连通的,且其外表面包含边缘;②在外表面中有顶点与当前顶点相邻,且这些顶点幸存沿着外表面的一条路径。对于每个至少有2个顶点的极大平面图,存在一个平面正则序。平面图的正则序要求输入图至少有2个顶点。在一些平面图绘制算法中,特别是那些创建直线嵌入的算法中,平面正则序被用作输入。时间复杂度为O(V+E)。
(4)void chrobak_payne_straight_line_drawing(const Graph& g, PlanarEmbedding perm, ForwardIterator ordering_begin, ForwardIterator ordering_end, PositionMap drawing, VertexIndexMap vm),平面图的直线图是使用直线段绘制每条边的平面图。由于所有边都是直线段,因此绘图完全由平面中顶点的位置决定。本算法通过将平面图中的n个顶点映射到(2n-4)(n-2)网格中的整数坐标,形成平面图的直线图。时间复杂度为O(V+E)。
(5)bool is_straight_line_drawing(const Graph& g, GridPositionMap drawing, VertexIndexMap vm),如果绘图是一个属性映射,对位置映射概念进行建模,则当绘图下的图形中的边所包含的两条线段没有相交时,函数返回true。此函数在存在自循环和平行边的情况下正确工作,可用于检验chrobak_payne_straight_line_embedding()函数的输出。时间复杂度为O(V
logV)。
(6)bool is_kuratowski_subgraph(const Graph& g, ForwardIterator begin, ForwardIterator end, VertexIndexMap vm),当在给定范围内定义的边序列在图中形成kuratowski子图时返回true。如果需要验证任意图是否有K5或K3,3次方,则应使用boyer_myrvold_planarity_test()函数来隔离这个次要子图。本函数的目的是帮助测试和检验boyer_myrvold_planarity_test()函数。本函数从给定的边序列中创建一个临时图,并反复收缩边,直到最后得到一个所有边都是3阶或所有边都是4阶的图。然后使用Boost的同构函数,对照K5或K3,3检查最终的收缩图。时间复杂度为O(V)。
(7)make_connected(Graph& g, VertexIndexMap vm, AddEdgeVisitor& vis),如果图上每一对顶点都有一条路径,则该无向图是连通的。该函数通过增加边来使输入图具有成为连通图的最小边数。该算法首先识别图中所有连通成分,然后添加边将这些成分连接在一条路径上。该函数默认行为是通过为每对顶点调用add_edge()来修改图。时间复杂度为O(V+E)。
(8)void make_biconnected_planar(Graph& g, PlanarEmbedding embedding, EdgeIndexMap em, AddEdgeVisitor& vis),如果图中每对顶点都有一个包含这对顶点的环,则该图是双连通的。该函数通过给输入的连通平面图添加边来使该图成为双连通的。该函数默认行为是通过为每对顶点调用add_edge()来修改图。时间复杂度为O(V)。
(9)void make_maximal_planar(Graph& g, PlanarEmbedding embedding, VertexIndexMap vm, EdgeIndexMap em, AddEdgeVisitor vis),如果一平面图没有更多的边(除了平行边和自身环)可以添加而不创建非平面图,则该平面图为最大平面图。根据欧拉公式,n个顶点的最大平面图总是有3n-6条边和2n-4个面。该函数的输入图必须是至少有3个顶点的双连通平面图。该函数默认行为是通过为每对顶点调用add_edge()来修改图。时间复杂度为O(V+E)。

算法17:其他算法。
(1)void metric_tsp_approx_from_vertex(const VertexListGraph& g, typename graph_traits::vertex_descriptor start, WeightMap weightmap, VertexIndexMap indexmap, TSPVertexVisitor vis),其是旅行售货员的启发式算法,用于生成一个全连通无向图作为旅行路线,该图的有权边服从三角形不等式。时间复杂度为O(ElogV)。
(2)sequential_vertex_coloring(const VertexListGraph& g, OrderPA order, ColorMap color),使用简单算法来计算图中顶点的着色。给定顶点顺序为v1,v2,…,vn,该算法指派顶点vk为最小可能的颜色,但该算法不保证得到最优着色。时间复杂度为O(V
(d+k)),其中d为顶点的最大度,k为使用的颜色数。
(3)edge_coloring(const Graph &g, ColorMap color),使用由Misra提出的算法,计算图中顶点的边着色。给定边顺序为e1,e2,…,en,该算法指派颜色以使不会有顶点与两个相同颜色的边连接。时间复杂度为O(|E|*|V|)。
(4)bool is_bipartite(const Graph& graph, const IndexMap index_map, PartitionMap partition_map),该函数使用基于深度优先搜索的着色方法测试图的二部性。如果一个无向图的顶点集可以划分为两个集合,使得每一条边都从一边转到另一边,则该无向图具有二部性。显然图的两个着色与图的划分是相同的,该函数测试这种双色着色是否可行。时间复杂度为O(V+E)。
(5)OutputIterator find_odd_cycle(const Graph& graph, const IndexMap index_map, PartitionMap partition_map, OutputIterator result),该函数使用基于深度优先搜索的着色方法来测试图是否具有二部性。其一个等价特征是奇数长度的环不存在,这意味着图是二部性当且仅当其不包含奇数顶点的环作为子图。该函数与is_bipartite()的功能相同,但如果发现图不具有二部性,则另外构造一奇数长度的环。时间复杂度为O(V+E)。
(6)void maximum_adjacency_search(const Graph& g, const bgl_named_params& params),该函数执行无向图中顶点的遍历。下一个访问的顶点是有最多访问邻接顶点的顶点。在一无权无向图中,图中最后访问的顶点的访问邻接顶点数,也是该顶点与访问的下个顶点间不相交边的路径数。时间复杂度为O(E+V)。
(7)void hawick_circuits(Graph const& graph, Visitor visitor, VertexIndexMap const& vim = get(vertex_index, graph)),该算法枚举有向多重图中的所有基本环。其还枚举由并行边引起的自环和冗余环。

你可能感兴趣的:(开课吧学习博客,数据结构)