图的类型定义
CreateGraph(&G,V,VR)
V:图的顶点集合
VR:图中弧的集合
DFSTraverse(G):深度优先遍历
BFSTraverse(G):广度优先遍历
图的存储结构
图的逻辑结构:多对多
图没有顺序存储结构,但可以借助二维数组来表示元素间的关系(邻接矩阵)
链式存储结构:多重链表(邻接表,邻接多重表,十字链表)
重点介绍:邻接矩阵(数组表示法)和邻接表(链式表示法)
邻接矩阵
1. 数组(邻接矩阵)表示法
建立一个顶点表(记录各个顶点信息)和一个邻接矩阵(表示各个顶点之间的关系)
无向图的邻接矩阵是对称的
顶点i的度=第i行(列)中1的个数
完全图的邻接矩阵中,对角元素为0,其余1
有向图的邻接矩阵中:
第i行含义:以结点vi为尾的弧(即出度边)
第i列含义:以结点vi为头的弧(即入度边)
网(即有权图)的邻接矩阵表示法
定义为A.arcs[i][j]=Wij/∞无边(弧)
结构体
#define MVNum 100 // 最大顶点数
typedef char VerTexType; // 设顶点的数据类型为字符型
typedef int ArcType; // 假设边的权值类型为整数
typedef struct {
VerTexType vexs[MVNum]; // 顶点表
ArcType arcs[MVNum][MVNum]; // 邻接矩阵
int vexnum, arcnum; // 图的当前点数和边数
}AMGraph;
采用邻接矩阵表示法创建无向网
算法思想
- 输入总顶点数和总边数
- 依次输入点的信息存入顶点表中
- 初始化邻接矩阵,使每个权值初始化为极大值
- 构造邻接矩阵,输入每条边所依附的顶点及边的权值
构造无向图时:初始化邻接矩阵权值均为0,构造邻接矩阵时权值为1
邻接矩阵的优点
直观,简单,好理解
方便检查任意一对顶点间是否存在边
方便找任一顶点的所有'邻接点'(有边直接相连的顶点)
方便计算任一顶点的度
无向图:对应行(或列)非0元素的个数
有向图:对应行非零元素的个数是出度,对应列非零元素的个数是入度
邻接矩阵的缺点
不便于增加和删除顶点
浪费空间-----存稀疏图有大量无效元素
存储稠密图很合适
浪费时间-----统计稀疏图中一共有多少条边
邻接表表示法
- 顶点:按编号顺序将顶点数据存储正在一维数组中
- 关联同一顶点的边(以顶点为尾的弧)—用线性链表存储
/*
* 图的邻接表
*/
typedef struct ArcNode{
int adjvex; // 边结点
struct ArcNode *nextarc; // 该边所指向的顶点的位置
OtherInfo info; // 和边相关的信息
}ArcNode;
typedef struct VNode{
VerTexType data; // 顶点信息
ArcNode *firstarc; // 指向第一条依附该顶点的边的指针
}VNode, AdjList[MVNum]; // AdjList表示邻接表类型
typedef struct {
AdjList vertices; // 邻接表类型的数组,存储所有顶点
int vexnum, arcnum; // 图的当前顶点数和弧数
}ALGraph;
无向图邻接表特点
- 邻接表不唯一
- 若无向图中有n个顶点,e条边,则其邻接表需n个头结点和2e个表结点,适宜存储稀疏图
- 无向图中顶点vi的度为第i个单链表中的结点数
有向图邻接表特点
- 找出度易,找出度难;可引用逆邻接表表示入度边
- 顶点vi的出度为第i个单链表中的结点个数
- 顶点vi的入度为整个单链表中邻接点域值是i-1的结点个数
采用邻接表表示创建无向网
算法思想
1. 输入总顶点数和总边数.
2. 建立顶点表
依次输入点的信息存入顶点表中
使每个表头结点的指针域初始化为NULL
3. 创建邻接表
依次输入每条边依附的两个顶点
确定两个顶点的序号i和j,建立边结点
将此边结点分别插入到vi和vj对应的两个边链表的头部
邻接表的优点
方便找任一顶点的所有邻接点
节约稀疏图的存储空间
需要N个头指针+2E个结点(每个结点至少2个域)
对无向图,邻接表方便计算任一顶点的度
对有向图,只能计算出度;如果需要计算入度,需要构造逆邻接表
邻接矩阵与邻接表表示法的关系
- 联系:邻接表中每个链表对应于邻接矩阵中的一行,链表中结点个数邓毅一行中非零元素的个数
- 区别:
- 对于任一确定的无向图,邻接矩阵是惟一的(行列号与顶点号一致),单邻接表不唯一(链接次序与顶点编号无关)
- 邻接矩阵的空间复杂度为O(n的平方),而邻接表的空间复杂度为O(n+e)
- 用途:邻接矩阵用于稠密图,而邻接表多用于稀疏图