算法与数据结构——图
图
图的基本概念
图的定义
图G由顶点集V和边集E组成,记为G = (V, E),其中V(G)表示图G中顶点的有限非空集;E(G)表示图G中顶点之间的关系(边)集合。若V={v1, v2, v3, ..., vn},则用|V|表示图G中顶点的个数,E = {(u, v) | u∈V, v∈V},用|E|表示图G中的边数。
图不可以为空,V一定是一个非空集,而E可以是一个空集。
有向图
若E是有向边(也称弧)的有限集合时,则图G为有向图。弧是顶点的有序对,记为<v, w>,其中v、w是顶点,v成为弧尾,w称为弧头,<v, w>称为从顶点v到顶点w的弧,也称v邻接w,或w邻接自v。
![](https://img2022.cnblogs.com/blog/2089334/202206/2089334-20220619143941527-934810927.png)
如上图所示,对于<A, E> E为弧尾,A为弧头
无向图
若E是无向边(简称边)的优先级和时,则图G为无向图。边是顶点的无序对,记为(v, w) 或 (w, v),因为(v, w) = (w, v),其中v、w是顶点。可以说顶点w和顶点v互为临界点。边(v, w)依附于顶点v和w,或者说边(v, w)和顶点v、w相关联。
![](https://img2022.cnblogs.com/blog/2089334/202206/2089334-20220619143706088-124128797.png)
简单图、多重图
一个图G如果满足:
- 不存在重复边
- 不存在顶点到自身的边
那么,称图G为简单图。
![](https://img2022.cnblogs.com/blog/2089334/202206/2089334-20220619144414108-105900171.png)
若图G中某两个顶点之间的边数大于1条,有允许顶点通过一条边与自身相连,则称图G为多重图。
![](https://img2022.cnblogs.com/blog/2089334/202206/2089334-20220619144442274-1501764526.png)
顶点的度、入度、出度
对于无向图:顶点的度是指依附于该顶点的边的条数,记为TD(V)
$$
\sum_{i=1}^{n}{TD(v_i)} = 2 |E|
$$
对于有向图:
入度是以顶点v为终点的有向边的数目,记为ID(V)
出度是以顶点v为起点的有向边的数目,记为OD(V)
顶点v的度等于其入度和出度之和,即TD(V) = ID(V) + OD(V)
在具有n个顶点、e条边的有向图中:
$$
\sum_{i=1}^{n}ID(v_i) = \sum_{i=1}^{n}OD(v_i) = e
$$
路径、路径长度和回环
顶点vp到顶点vq之间一条路径是指顶点序列。当然,关联的边也可以理解为路径的构成元素。
路径上边的数目称为路径长度。
第一个顶点和最后一个顶点相同的路径称为回路或环
图的存储及基本操作
邻接矩阵法
![](https://img2022.cnblogs.com/blog/2089334/202206/2089334-20220619163710817-596461260.png)
0表示无边
1表示有边
对于无向图来说,第i个结点的度就是第i行或第i列非零元素的个数。
对于有向图来说,第i个结点的出度是第i行非零元素的个数;第i个结点的入度是第i列所对应元素的个数。
#define MaxVertexNum 100
typedef struct {
// 顶点表
char Vex[MaxVertexNum];
// 邻接矩阵,边表
bool Edge[MaxVertexNum][MaxVertexNum];
// 图的当前顶点数和边数/ 弧数
int vexNum, arcNum;
}MGraph;
邻接矩阵法存储带权图
![](https://img2022.cnblogs.com/blog/2089334/202206/2089334-20220619164733785-1307861441.png)
在对应位置写两个顶点之间对应的权值。如果两个顶点不存在边,则存放一个无穷大值。
#define MaxVertexNum 100
// 宏定义常量“无穷”
#define INFINITY 99999
// 顶点数据类型
typedef char VertextType;
// 带权图中边上权值的数据类型
typedef int EdgeType;
typedef struct {
VertexType Vex[MaxVertexNum];
EdgeType Edge[MaxVertexNum][MaxVertexNum];
int vexnum, arcnum;
}MGraph;
邻接矩阵法的性能分析
空间复杂度:
$$
O(|V|^2)
$$
只和定点数相关,和实际的边数无关。
适合用于稠密图。
无向图的邻接矩阵是对称矩阵,可以使用压缩存储(只存储上三角或下三角)的方法进行存储。
邻接矩阵法的性质
设图G的邻接矩阵为A,则An的元素An[i][j]等于由顶点i到顶点j的长度为n的路径的数目。
邻接表法
顺序 + 链式 存储方式
![](https://img2022.cnblogs.com/blog/2089334/202206/2089334-20220619170314623-1040541661.png)
![](https://img2022.cnblogs.com/blog/2089334/202206/2089334-20220619170353265-1910744256.png)
在无向图中,遍历某个顶点的边链表,边链表的个数就是其顶点的度。
而在有向图中:遍历某个顶点的边链表,边链表的个数就是其顶点的出度;如果需要求顶点的入度,需要遍历所有顶点,事件花费较高。
图的邻接表表示方式不唯一。
邻接表法性能分析
对于有向图,其空间复杂度为:
$$
O(|V|+|E|)
$$
对于无向图,其空间复杂度为:
$$
O(|V| + 2|E|)
$$
十字链表(理解)
存储有向图
![](https://img2022.cnblogs.com/blog/2089334/202206/2089334-20220619171450825-1478455131.png)
邻接多重表(理解)
存储无向图
![](https://img2022.cnblogs.com/blog/2089334/202206/2089334-20220619172057685-1775506636.png)
空间复杂度为 O(|V| + |E|)
图的基本操作
- Adjacent(G, x, y)——判断图G是否存在边<x, y>或(x, y)
- Neighbors(G, x)——列出图G中与结点x邻接的边
- InsertVertex(G, x)——在图G中插入顶点x
- DeleteVertex(G, x)——在图G中删除顶点x
- AddEdge(G, x, yS)——若无向边(x, y)或有向边<x, y>不存在,则向图G中添加该边