数据结构——图
一、图的基本概念
(一)图的特点
多对多
- 顶点之间的关系是任意的
- 图中任意两个顶点之间都可能相关
- 顶点的前驱和后继个数无限制
- 定义:
图是一种:数据元素间存在多对多关系的数据结构加上一组基本操作构成的抽象数据类型 - 弧:
<v,w>表示从v到w的一条弧,且称v为弧尾,称W为狐头,此时的图称为有向图 - 无向图:
指的是没有方向的序对 - 完全图:
有 n(n-1)/2 条边的无向图(即:每两个顶点之间都存在着一条边)称为完全图。 - 有向完全图:
有**n(n-1)**条弧的有向图(即:每两个顶点之间都存在着方向相反的两条弧) - 稀疏图:含有很少条边或弧的图。
- 稠密图:含有很多条边或弧的接近完全图的图。
- 权:与图的边或弧相关的数,这些数可以表示从一个顶点到另一个顶点的距离或耗费。
- 网:带权的图
- 邻接点:若 (v, v´) 是一条边,则称顶点 v 和 v´互为 邻接点,或称 v 和 v´相邻接;
称(v, v´) 依附于顶点 v 和 v´,或称 (v, v´) 与顶点 v 和 v´ 相关联。 - 有向图和无向图里面每个顶点的度的和除以2,就是边数。
- 连通图:图中任意两个顶点都是联通的
- 非连通图:有n个顶点和小于n-1条边的图;如果图有小于n-1条变,他一定不是连通图,有大于等于n-1条边不一定是连通图
- 连通分量:无向图的极大连通子图(不存在包含它的 更大的连通子图);任何连通图的连通分量只有一个,即 其本身;非连通图有多个连通分量(非连通图的每一个连 通部分)。
- 生成树:所有顶点均由边连接在一起但是不存在回路的图
- 注:
- 一个图可以有许多棵不同的生成树。
- 所有生成树具有以下共同特点:
- 生成树的顶点个数与图的顶点个数相同;
- 生成树是图的极小连通子图;
- 一个有 n 个顶点的连通图的生成树有** n-1 条边**;
- 生成树中任意两个顶点间的路径是唯一的;
- 在生成树中再加一条边必然形成回路。
- 生成树一定有n-1条边,有n-1条边不一定是生成树!!!
- 生成森林:对于非连通图,其每个连通分量可以构造 一棵生成树,合成起来就是一个生成森林。
- 有向树:如果一个有向图恰有一个顶点的入度为 0 , 其余顶点的入度均为 1 ,则是一棵有向树。
- 有向图的生成森林:由若干棵有向树组成,含有图中全部顶点,但只有足以构成若干棵不相交的有向树的弧。
二、图的存储结构
(一)数组表示法(邻接矩阵表示法)
1. 特点
- 无向图的**邻接矩阵对称**,可压缩存储;有 **n 个顶点**的无 向图所需**存储空间为 n(n-1)/2**。
- **有向图的邻接矩阵不一定对称**;有** n 个顶点的有向图所 需存储空间为 n²**,用于稀疏图时空间浪费严重。
- 无向图中**顶点 vi 的度 TD(vi) 是邻接矩阵中第 i 行 1 的个数**。
- 有向图中:顶点vi的**出度**是邻接矩阵中第i行1的个数;顶点vi的入度是邻接矩阵中第i列1的个数。
2. 图的数组(邻接矩阵)存储表示
#define INFINITY INT_MAX // 最大值∞
#define MAX_VERTEX_NUM 20 // 最大顶点个数
typedef enum {DG, DN, UDG, UDN} GraphKind;
//{有向图,有向网,无向图,无向网}
typedef struct ArcCell {
VRType adj; // VRType是顶点关系类型。对无权图用1或0表示相邻否;
// 对带权图,则为权值类型。(表示有无与其相连的节点)
InfoType *info; // 该弧相关信息的指针(可有可无)
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; // 顶点向量
AdjMatrix arcs; // 邻接矩阵
int vexnum, arcnum; // 图的当前顶点数和弧(边)数
GraphKind kind; // 图的种类标志
} MGraph;
3. 邻接表(类似于树的孩子链表表示法)
(1) 分为两个节点:头结点:含有两个域一个数据域用来存储vi的名或其他有关的信息
表结点:含有三个域,分别是邻接点域,用来存放与vi邻接的顶点在表头数组中的位置;链域:用来指示下一条边或弧。info域用来存储与边或弧相关的信息,如权值等等
info:书上是如权值等 ,如果是个实际问题,比如求带限制条件的最短路径或者最小生成树,那么就可加上Info信息。
(2) 特点:
- 若无向图中有 n 个顶点、e 条边,则其邻接表需 n 个头结点和 2e 个表结点。适宜存储稀疏图。
- 无向图中顶点 vi 的度为第 i 个单链表中的结点数。
邻接表的特点(找出度容易,找入度难): - 顶点 vi 的出度为第 i 个单链表中的结点个数。
- 顶点 vi 的入度为整个单 链表中邻接点域值是 i-1 的结点个数。
逆邻接表的特点(找入度容易,找出度难): - 顶点 vi 的入度为第 i 个 单链表中的结点个数。
- 顶点 vi 的出度为整个单 链表中邻接点域值是 i-1 的结点个数。
所以根据入度与出度的要求不同,需要设计不同的邻接表
(3)图的邻接表的存储表示
#define MAX_VERTEX_NUM 20
typedef struct ArcNode {
int adjvex; // 该弧所指向的顶点的位置
struct ArcNode *nextarc; // 指向下一条弧的指针
InfoType *info; // 该弧相关信息的指针
} ArcNode;
typedef struct VNode {
VertexType data; // 顶点信息
ArcNode *firstarc; // 指向第一条依附该顶点的弧
} VNode, AdjList[MAX_VERTEX_NUM];
typedef struct {
AdjList vertices;
int vexnum, arcnum; // 图的当前顶点数和弧数
int kind; // 图的种类标志
} ALGraph;
4、十字链表
顶点节点:数据域、第一条入弧(firstin)、第一条出弧(firstout)
- 弧节点:弧尾位置(tailvex)、狐头位置(headvex)、弧头相同的下一条弧(hlink)、弧尾相同的下一条弧(tlink)
- 注意:如果所画的十字链表下一个为空,就要表示出来在图中
- 有向图的十字链表存储表示:
#define MAX_VERTEX_NUM 20
typedef struct ArcBox {
int tailvex, headvex; // 该弧的尾和头顶点的位置
struct ArcBox *hlink, *tlink;
// 分别指向下一个弧头相同和弧尾相同的弧的指针域
InfoType *info; // 该弧相关信息的指针
} ArcBox;
typedef struct VexNode {
VertexType data;
ArcBox *firstin, *firstout; // 分别指向该顶点第一条入弧和出弧
} VexNode;
typedef struct {
VexNode xlist[MAX_VERTEX_NUM]; // 表头向量
int vexnum, arcnum; // 有向图的当前顶点数和弧数
} OLGraph;
5、邻接多重表(无向图的另一种链式存储结构)
不讲
7、图的遍历
7.3.1 深度优先遍历
连通图的深度优先遍历类似于树的先根遍历
方法:1、访问指定的起始顶点;
2、若当前访问的顶点的邻接顶点有未被访问的,则任选 一个访问之,转2;反之,退回到最近访问过的顶点;直到与起始顶点相通的全部顶点都访问完毕;
3、若此时图中尚有顶点未被访问,则再选其中一个顶点 作为起始顶点并访问之,转 2; 反之,遍历结束。
7.3.2 广度优先遍历
方法:从图的某一结点出发,首先依次访问该结点的所有邻 接顶点 Vi1, Vi2, …, Vin 再按这些顶点被访问的先后次序依次访问 与它们相邻接的所有未被访问的顶点,重复此过程,直至所有顶 点均被访问为止。
实现:用队列进行实现,如果一个节点没有孩子则队头就进行出队操作;
7.4.3 最小生成树
最小生成树:给定一个无向网络,在该网的所有生成 树中,使得各边权数之和最小的那棵生成树称为该网的最 小生成树,也叫最小代价生成树。
- 生成树:所有顶点均由边连接在一起但不存在回路的图。
- 一条性质:一个有 n 个顶点的连通图的生成树有 n-1 条边;