数据结构——图(存储结构)

图的定义和基本术语


:G=(V,E)  Grapg = (Vertex, Edge)
  V:顶点(数据元素)的有穷非空集合;
  E:边的有穷集合

无向图:每条边都是无方向的
有向图:每条边都是有方向的
在这里插入图片描述
完全图:任意两点都有一条边相连
在这里插入图片描述
稀疏图:有很少边或弧的图(e < nlogn
稠密图:有较多边或弧的图
:  边/弧带权的图
邻接: 有边/弧相连的两个顶点之间的关系
    存在(vi,vj),则称vi和vj互为邻接点;
    存在<vi,vj>,则称vi邻接到vj,vj邻接于vi
关联(依附):边/弧与顶点之间的关系
顶点的度:与该顶点相关联的边的数目,记为TD(v)
有向图中,顶点的度等于该顶点的入度出度之和
顶点 v 的入度是以 v 为重点的有向边的条数,记作 ID(v)
顶点 v 的出度是以 v 为始点的有向边的条数,记作 OD(v)
在这里插入图片描述

路径:接续的边构成的顶点序列
路径长度:路径上边或弧的数目/权值之和
回路(环):第一个顶点和最后一个顶点相同的路径
简单路径:除路径起点和终点相同外,其余顶点均不相同的路径
在这里插入图片描述
连通图(强连通图)
  有无(有)向图G =(V,{E})中,若对任何两个顶点 v、u 都存在从 v 到 u 的路径,则称G是连通图(强连通图)
在这里插入图片描述
权与网:
  图中边或弧所具有的的相关数称为,表明从一个顶点到另一个顶点的距离或耗费;带权的图称为

子图:
  设G =(V,{E})、G1 =(V1,{E1}),若V1⊆ V,E1⊆E,则称G1是G的子图
在这里插入图片描述
连通分量(强联通分量)

  • 无向图G的极大连通子图称为G的连通分量
    极大连通子图意思是:该子图是G连通子图,将G的任何不在该子图中的顶点加入,子图不再连通
    在这里插入图片描述

  • 有向图G的极大强连通子图称为G的强连通分量
    极大强连通子图意思是:该子图是G的强连通子图,将D的任何不在该子图中的顶点加入,子图不再是强连通的
    在这里插入图片描述

极小连通子图:该子图是G的连通子图,在该子图中删除任何一条边,子图不再连通
生成树:包含无向图G 所有顶点的极小连通图
生成森林:对非连通图,由各个连通分量的生成树的集合
在这里插入图片描述

图的类型定义


图的抽象数据类型定义如下:

ADT Graph{
  数据对象V:具有相同特性的数据元素的集合,称为顶点集
  数据关系R:R = {VR}
  VR = {<v,w>|<v,w>| v,w∈V ^ p(v,w),
  <v,w>表示从v到w的弧,p(v,w)定义了弧<v,w>的信息
  }
  CreateGraph(&G, V, VR)
    初始条件:V是图的顶点集,VR是图中弧的集合
    操作结果:按V和VR的定义构造图G
  DFSTraverse(G)
    初始条件:图G存在
    操作结果:按图进行深度优先遍历
  BFSTraverse(G)
    初始条件:图G存在
    操作结果:对图进行广度优先遍历
}ADT Graph

图的存储结构


图的逻辑结构:多对多

数组(邻接矩阵表示法)

  • 建立一个顶点表(记录各个顶点信息)和一个邻接矩阵(表示各个顶点之间关系)
    • 设图 A = (V,E)有n个顶点,则
      在这里插入图片描述
    • 图的邻接矩阵是一个二维数组 A.arcs[n][n],定义为:在这里插入图片描述

在这里插入图片描述
分析1:无向图的邻接矩阵是对称
分析2:顶点i的 = 第 i 行(列)中 1 的个数
特别:完全图的邻接矩阵中,对角元素为0,其余为1


在这里插入图片描述
:在有向图的邻接矩阵中,
  第 i 行含义:以结点vi为尾的弧(即出度边)
  第 i 列含义:以结点vi为头的弧(即入度边)

分析1:有向图的邻接矩阵可能是不对称的
分析2:顶点的出度 = 第 i 行元素之和
     顶点的入度 = 第 i 列元素之和
     顶点的度 = 第 i 行元素之和 + 第 i 列元素之和

网(即有权图)的邻接矩阵表示法

在这里插入图片描述
在这里插入图片描述
邻接矩阵的存储表示:用两个数组分别存储顶点表邻接矩阵

#define MaxInt 32767	//表示极大值,即∞
#define MVNum 100		//最大顶点数
typedef char VerTexType;	//设顶点的数据类型为字符型
typedef int ArcType;	//假设边的权值类型为整型

typedef struct{
	VerTexType vexs[MVNum];		//顶点表
	ArcType arcs[MVNum][MVNum];		//邻接矩阵
	int vexnum, arcnum;		//图的当前点数和边数
}AMGraph;	// Adjacency Matrix Graph


采用邻接矩阵表示法创建无向网

在这里插入图片描述

算法思想:

  1. 输入总顶点数和总边数
  2. 依次输入点的信息存入顶点表
  3. 初始化邻接矩阵,使每个权值初始化为极大值
  4. 构造邻接矩阵
//采用邻接矩阵表示法,创建无向网G
Status CreateUDN(AMGraph &G){
	cin >> G.vexnum >> G.arcnum;	//输入总顶点数,总边数
	for(i = 0; i < G.vexnum; ++i)
		cin >> G.vexs[i];			//依次输入点的信息
	for(i = 0; i < G.vexnum; ++i)	//初始化邻接矩阵
		for(j = 0; j < G.vexnum; ++j)
			G.arcs[i][j] = MaxLnt;		//边的权值均置为极大值
	
	//构造邻接矩阵
	for(k = 0; k < G.arcnum; ++k){
		cin >> v1 >> v2 >> w;		//输入一条边所依附的顶点及边的权值
		i = LocateVex(G, v1);
		j = LocateVex(G ,v2);		//确定v1和v2在G中的位置
		G.arcs[i][j] = w;			//边<v1, v2>的权值置为w
		G.arcs[j][i] = G.arcs[i][j];		//置<v1, v2>的对称边<v2, v1>的权值为w
	}
	return OK;
}//CreateUDN

补充算法:在图中查找顶点

//在图G中查找顶点u,存在则返回顶点表中的下标;否则返回-1
int LocateVex(AMGraph G, VertexType u){
	int i;
	for(i = 0; i < G.vexnum; ++i)
		if(u == G.vexs[i])	return i;
	return -1;
}


在这里插入图片描述
在这里插入图片描述

邻接表

邻接表表示法(链式)
  • 顶点:按编号顺序将顶点数据存储在一维数组中
  • 关联同一顶点的边(以顶点为尾的弧):用线性链表存储

无向图

在这里插入图片描述
特点:

  • 邻接表不唯一
  • 无向图中有n个顶点、e条边,则其邻接表需n个头结点和2e个表结点。适宜存储稀疏图
  • 无向图中顶点vi的度为第i个单链表中的结点数

有向图
在这里插入图片描述

特点:

  • 顶点vi出度为第 i 个单链表中的结点个数
  • 顶点vi入度为整个单链表中邻接点域值是 i - 1 的结点个数(需要遍历整个链表)

在这里插入图片描述
特点:

  • 顶点vi入度为第 i 个单链表中的结点个数
  • 顶点vi出度为整个单链表中邻接点域值是 i - 1 的结点个数(需要遍历整个链表)

在这里插入图片描述

图的邻接表存储表示

在这里插入图片描述

typedef struct VNode{
	VerTexType data;		//顶点信息
	ArcNode * firstarc;		//指向第一条依附该顶点的边的指针
}VNode, AdjList[MVNum]		//AdjList表示邻接表类型

说明: 例如 AdjList v;    相当于:VNode v[MVNum];
在这里插入图片描述

#define MVNum 100				//最大顶点数
typedef struct ArcNode{			//边结点
	int adjvex;					//该边所指向的顶点的位置		
	struct ArcNode * nextarc;	//指向下一条边的指针
	OtherInfo info;				//信息域;存储和边相关的信息
}ArcNode;

图的结构定义:

typedef struct{
	AdjList vertices;		//vertices--vertex的复数
	int vexnum, arcnum;		//图的当前顶点数和弧数
}ALGraph;

在这里插入图片描述

采用邻接表表示法创建无向网

算法思想:

  1. 输入总顶点数总边数
  2. 建立顶点表
    依次输入点的信息存入顶点表
    使每个表头结点的指针域初始化为NULL
  3. 创建邻接表
    依次输入每条边依附的两个顶点
    确定两个顶点的序号 i 和 j,建立边结点
    将此边结点分别插入到vi和vj对应的两个边链表的头部
//采用邻接表表示法,创建无向图G
Status CreateUDG(ALGraph &G){
	cin >> G.vexnum >> G.arcnum;		//输入总顶点数、总边数
	
	for(i = 0; i < G.vexnum; ++i){		//输入各点,构造表头结点表
		cin >> G.vertices[i].data;		//输入顶点值
		G.vertices[i].firstarc = NULL;	//初始化表头结点的指针域
	}//for
	
	for(k = 0; k < G.arcnum; ++k){		//输入各边,构造邻接表
		cin >> v1 >> v2;				//输入一条边依附的两个顶点
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		p1 = new ArcNode;				//生成一个新的边结点*p1
		p1 -> adjvex = j;				//邻接点序号为j
		p1 -> nextarc = G.vertices[i].firstarc;
		G.vertices[i]firstarc = p1;		//将新结点*p1插入顶点vi的边表头部
		p2 = new ArcNode;				//生成另一个对称的新的边结点*p2
		p2 -> adjvex = i;				//邻接点序号为i
		p2 -> nextarc = G.vertices[j].firstarc;
		G.vertices[j].firstarc = p2;	//将新结点*p2插入顶点vj的边表头部
	}//for
	return OK;
}

在这里插入图片描述

邻接矩阵与邻接表表示法的关系

在这里插入图片描述

  1. 联系:邻接表每个链表对应于邻接矩阵中的一行,链表中结点个数等于一行中非零元素的个数
  2. 区别:
    ① 对于任一确定的无向图,邻接矩阵是唯一的(行列号与顶点编号一致),但邻接表不唯一(链接次序与顶点编号无关)
    ② 邻接矩阵的空间复杂度为O(n2),而邻接表的空间复杂度为O(n+e)
  3. 用途:邻接矩阵多用于稠密图;而邻接表多用于稀疏图


十字链表——用于有向图

在这里插入图片描述
  十字链表(Orthogonal List)是有向图的另一种链式存储结构,可以将它看成有向图的邻接表逆邻接表结合起来形成的一种链表

  有向图中的每一条弧对应十字链表中的一个弧结点,同时有向图中的每个顶点在十字链表中对应有一个结点,叫做顶点结点

在这里插入图片描述
在这里插入图片描述

邻接多重表(无向图的另一种链式存储结构)

邻接表优点:容易求得顶点和边的信息
   缺点:某些操作不方便(如:删除一条边需找表示此边的两个结点)

邻接多重表:

在这里插入图片描述

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值