CHAPTER_10 提高篇(4)——图算法专题
10.1图的定义和相关术语
图(Graph)是由顶点和连接顶点的边构成的离散结构。在计算机科学中,图是最灵活的数据结构之一,很多问题都可以使用图模型进行建模求解。
图的结构很简单,就是由顶点V集和边E集构成,因此图可以表示成 。
一般来说,图可以分为有向图和无向图。有向图是所有边都有方向,即确定了一个顶点到另一个顶点的指向;而无向图的所有边都是双向的,即无向图的所有边都是双向的。
顶点的度是指和该顶点相连的边的条数。对于有向图来说,顶点的出边条数称为该顶点的出度,入边条数称为该顶点的入度。例如对于上面的无向图,顶点V3的度为3;对于上面的有向图,顶点V1的出度为2,入度为1。
顶点和边都可以有一定属性,而量化的属性称为权值,顶点的权值和边的权值分别称为点权和边权。
10.2.1图的存储——邻接矩阵
设图G(V,E)的顶点标号为0,1,2,...,N-1。那么可令二维数组G[N][N]的两维分别表示图的顶点标号,这个二维数组称为邻接矩阵。对于一个无向图,如果G[i][j]=1,说明顶点i和j有边;如果G[i][j]=0,说明顶点i和j无边。对于一个有向图,如果G[i][j]=1,说明顶点i到顶点j有边;如果G[i][j]=0,说明顶点i到j无边。
下图为图的邻接矩阵表示示例:
虽然邻接矩阵实现简单,但是由于需要开一个二维数组,如果顶点数目过大,会带来很大的空间消耗。因此邻接矩阵知识和用于顶点数目不大(一般不超过1000)的情况。
10.2.2图的存储——邻接表
假设有向图G(V,E)的顶点标号为0,1,2,...,N-1。每个顶点可能有若干条出边,如果把同一个顶点的所有出边放在一个列表中,那么N个顶点就会有N个列表(没有出边,则对应空表)。这N个列表被称为图的邻接表,记为Adj[N],其中Adj[i]存放顶点i的所有出边组成的列表,这样Adj[0],Adj[1],...,Adj[N-1]分别都是一个列表。
例如上图中,顶点V1的出边有V2、V3,因此Adj[0]的列表中有2(代表顶点3)和1(代表顶点2);而V2没有出边,故Adj[1]中没有元素。
至此,我们需要解决邻接表中每个列表的实现。最容易想到的方式是用链表实现,实际上我们有更简单的实现方式—vector。开一个vector变长数组Adj[N],这样每个Adj[i]都代表着顶点i-1的出边。
vector<int> Adj[N];
如果想要添加一条从1号顶点到3号顶点的边,只需在vector[1]中添加元素即可:
Adj[1].push_back(3);
如果需要同时存放边的终点编号与权值,那么可以建立结构体:
struct Node {
int v; //边的终点编号
int w; //边的权值
Node(){} //构造函数
Node(int _v,_w) {
v=_v;
w=_w;
}
};
vector<Node> Adj[N];
如果想要添加从编号1的顶点到编号3的顶点的有向边,并且边权为4,可以如下:
Adj[1].push_back(Node(3,4));