文章目录
一、图的定义和基本术语
图的基本定义
图(Graph)是由顶点的有穷非空集合和顶点之间的边组成,通常表示为:G(V,E),其中,G 表示一个图,V 是图 G 中顶点的集合,E 是图 G 中边的集合。
1.线性表中将数据元素叫元素,树中将数据元素叫结点,在图中数据元素称之为顶点(Vertex)。
2.顶点集合 V 有穷非空。
3.图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的。
图的基本术语
无向边: 若顶点 vi 到 vj 之间的边没有方向,则称这条边为无向边(Edge),用无序偶对(vi,vj)来表示。 如果图中任意两个顶点之间的边都是无向边,则称该图为无向图。
无向完全图:在无向图中,如果任意两个顶点之间都存在边,则称该图为无向完全图。
有向边:若顶点 vi 到 vj 之间的边有方向,则称这条边为有向边,也称为弧(Arc),用有序偶对 <vi,vj> 来表示。
有向完全图:在有向图中,如果任意两个顶点之间都存在方向互为相反的两条弧,则称该图为有向完全图。
简单图:在图中,若不存在顶点到此结点自身的边,且同一条边不重复出现,则称这样的图为简单图。
稀疏图和稠密图:有很少条边的图称为稀疏图,反之称为稠密图。这里的稀疏和稠密是模糊的概念,都是相对而言的。
权和网:有些图的边或弧具有与它相关的数字,这种与图的边或弧相关的数叫做权(Weight)。这些权可以表示从一个顶点到另一个顶点的距离或耗费。这种带权的图通常称为网(Network)。
回路和环:第一个顶点和最后一个顶点相同的路径称为回路或环
连通,连通图和连通分量:在无向图 G 中,如果顶点 v 到顶点 v’ 有路径,则称 v 和 v’ 是连通的。如果对于图中任意两个顶点 vi、vj ∈ V,vi 和 vj 都是连通的,则称 G 是连通图(Connected Graph)。无向图中的极大连通子图称为连通分量。
注意连通分量的概念,他强调:
1、要是无向图的子图;
2、子图要是连通的;
3、连通子图含有极大顶点数;
4、具有极大顶点数的连通子图包含依附于这些顶点的所有边。
例如,下图(1)不是连通图,而图(2)和(3)是图(1)的两个连通分量。
强连通图和强连通分量:在有向图 G 中,如果对于每一对 vi、vj ∈ V,vi ≠ vj ,从 vi 到 vj 和从 vj 到 vi 都存在路径,则称 G 是强连通图。有向图中的极大强连通子图称为强连通分量。
例如,下图(a)并不是强连通图,因为顶点 b 到顶点 a 路径不存在。图(b)和单独一个b顶点就是是图(a)的强连通分量。
连通图的生成树:连通图的生成树是一个极小的连通子图,它含有图中全部的 n 个顶点,但只有足以构成一棵树的 n-1 条边。
如下图2就是图1的生成树
有向树和生成森林:如果一个有向图恰有一个顶点的入度为 0,其余顶点的入度均为 1,则是一颗有向树。一个有向图的生成森林由若干颗有向树组成,含有图中全部顶点,但只有足以构成若干颗不相交的有向树的弧。
二、图的存储结构
邻接矩阵
图的邻接矩阵(Adjacency Matrix)存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(称为邻接矩阵)存储图中的边或弧的信息。
类型定义
#define maxint 32767//表示最大值,即无穷
#define maxsize 100//表示最大顶点数
typedef struct {
char vexs[maxsize];//顶点数据类型为字符型
int arcs[maxsize][maxsize];//边的权值类型为整型
int vexnum, arcnum;//图的顶点数和边数
}AMGraph;
采用邻接矩阵法构建无向图(存在伪代码)
void createUND(AMGraph& g) {
cin >> g.vexnum >> g.arcnum;
for (int i = 0; i < g.vexnum; i++)//输入顶点信息
cin >> g.vexs[i];
for (int i = 0; i < g.vexnum; i++)//边初始化
for (int j = 0; j < g.vexnum; j++)
g.arcs[i][j] = maxint;
for (int k = 0; k < g.arcnum; k++) {
cin >> v1 >> v2 >> w;//输入两个顶点和边的权值
i = locatevex(g, v1), j = locatevex(g, v2);//找出两个顶点在g中的位置
g.arcs[i][j] =g.arcs[j][i]= w;
}
}
时间复杂度为O(n^2)
若要构建有向图,只需初始化邻接矩阵时,将边的权值均初始化为0,稍加修改即可
邻接矩阵的优缺点:
优点:
1.便于判断两个顶点之间是否有边,根据arcs[i][j]来判断即可
2.便于计算各个顶点的度。对于无向图,邻接矩阵第i行元素之和就是顶点i的度;对于有向图,第i行就是该元素的出度,第i列就是该元素的入度。
缺点:
1.不便于增加和删除顶点
2.不便于统计边的数目。需要扫描邻接矩阵所有元素才能统计完毕,时间复杂度为O(n^2)
3.空间复杂度高
邻接表
邻接表(Adjacency List)是图的一种链式存储方法;在邻接表中对于图 G 中的每个顶点 vi 建立一个单链表,把与vi相邻的顶点放在这个链表中。邻接表中每个单链表的第一个结点存放有关顶点的信息,把这一结点看成链表的表头,其余结点存放有关边的信息,这样邻接表就由两部分组成:表头结点表和边表。
表头结点表:由所有表头结点以顺序结构形式存储,以便可以随机访问任何一个顶点的边链表。表头结点包括数据域和链域两部分。
边表:边链表包括邻接点域(adjvex)和数据域和链域三个部分;邻接点域存储与顶点vi邻接的点在图中的位置;数据域存储和边相关的信息,如权值等;链域存储与顶点vi邻接的下一个结点;
类型定义
#define maxsize 100//表示最大顶点数
typedef struct ArcNode {
int adjvex;//该边所指的顶点位置
struct ArcNode* nextarc;//指向下一条边的指针
int info;//和边相关的信息
};
typedef struct VNode{
char data;//顶点信息
ArcNode* firstarc;//指向第一条依附该顶点的边的指针
}VNode,AdjList[maxsize];
typedef struct {
AdjList vertices;
int vexnum, arcnum;//图的顶点数和边数
}ALGraph;
采用邻接表创建无向图
void createUDG(ALGraph& g) {
cin >> g