数据结构 第五章 图——基本概念,两种存储方式

图(Graph)的定义:
图G由一组顶点(顶点集)V(vertex)和一组边(边集)E(Edge)组成,记做G( V, E ),边是顶点对( v, w )∈ E,用|V|表示顶点的个数,|E|表示边的个数。

无向边:( v, w )用圆括号,表示顶点v和顶点w之间的边没有方向;
有向边:< v, w > 用尖括号,表示从顶点v指向顶点w的边(单行线)。

类型名称:图.
数据对象集:G(V, E)由一个非空的有限顶点集合V和一个有限边集合E组成(图可以没有边,但至少有一个顶点)。
数据操作集:
放在后面内容中(与存储的内容放在一起)。

基础部分涉及的相关术语:
(1)无向图:若E是无向边的有限集合时,则图为无向图。
(2)有向图:若E是有向边(也成弧,如< v, w > 中顶点v称为弧尾,顶点w称为弧头,也称作w邻接自v)的有限集合时,则图为有向图。
(3)简单图:满足没有重复边和自回路的图称为简单图。
(4)顶点的度(TD)、入度(OD)和出度(ID):图中每个顶点的度定义为以该顶点为端点的边的数目,在无向图中就是每个顶点所连接的边,在有向图中顶点的度分为出度和入度,出度是以该顶点作为弧尾的边的数目,入度,是以该顶点作为弧头的边的数目。
(5)边的权和网:如果一个图中的每条边上都可以标有具有某种含义的数值,则该数值为该边的权值,边上带有有权值的图称为带权图或网络。
(6)稠密图和稀疏图:边数很少的图称为稀疏图,边数很多的图称为稠密图,一般当图满足|E| < |V|log|V|时可以将图视为稀疏图。
(7)完全图:无向图中若任意两个顶点之间都存在边则称该图为无向完全图,有向图中若任意两个顶点间都存在方向相反的两条弧则成为有向完全图。

图的存储方式:
(1)邻接矩阵表示法:
用一个一维数组来存储顶点的信息,用一个二维数组来存储边的信息(即各顶点之间的邻接关系)。

#define MaxVertexNum 100
#define VertexType char
#define EdgeType int

typedef struct{
	VertexType Vex[MaxVertexNum];
	EdgeType Edge[MaxVertexNum][MaxVertexNUm];
	int vernum;
	int arcnum;
}Graph;

无权图中如果两个顶点之间有边相连,则让矩阵元素为1,否则为0。
带权图中如果两个顶点之间右边相连,则让矩阵元素为该边的权值,否则为0或无穷大。
邻接矩阵表示法的特点:
(1)无向图的邻接矩阵是对称矩阵,所以,实际存储时只需存储上三角或下三角元素,否则就有一半的空间被浪费;
(2)如果没有自回路现象,那么矩阵主对角线元素为0;
(3)对于无向图,邻接矩阵第i行(或列)元素的非0非无穷大的元素个数就是第i个顶点的度;
(4)对于有向图,邻接矩阵第i行元素的非0非无穷大元素个数是第i个顶点的出度,第i列元素中的非0非无穷大元素个数是第i个顶点的入度。
邻接矩阵的好处:
(1)直观、简单、好理解;
(2)方便检查一对顶点间是否存在边(只需查看邻接矩阵中对应矩阵元素的值即可);
(3)方便找出任一顶点的所有邻接点;
(4)方便计算任一顶点的度。
邻接矩阵的缺点:
(1)当图为稀疏图时有大量无效元素导致空间浪费;
(2)当统计图中一共有多少条边时需要对按行、列对每个元素进行查看,时间代价大,尤其是稀疏图时很浪费时间。

邻接表:

//邻接表
#define MaxVertexNum 100
typedef struct ArcNode{  //边表结构 
	int adjvex;
	struct ArcNode *next;
}ArcNode;
typedef struct VNode{    //顶点表结构 
	VertexType data;
	ArcNode *first;
}VNode;

typedef struct{          //图结构 
	VNode AdjList[VertexNum];
	int vernum, arcnum;
}AlGraph; 

邻接表存储方法特点:
(1)若为无向图,所需存储空间为O(|V| +2|E|)(存储每个顶点一次,每条边两次),若为有向图,则所需存储空间为O(|V|+|E|)(存储每个顶点每条边各一次);
(2)邻接表存储很方便寻找给定顶点的邻接点,但如果要确定给定两个顶点是否存在边,则比较麻烦;
(3)如果是无向图,那么邻接表也方便求给定顶点的度,但如果是有向表,则之方便求给定顶点的出度,入度则需要遍历整个图的所有邻接表,也可以采用构造逆邻接表(在顶点的邻接表中存储入度对应的顶点)的方法;
(4)图的邻接表不唯一,与建立邻接表的算法和边的输入次序有关。

图的操作集:

typedef Graph* G;
void CreatGraph( G ptrg );                              //创建图 
int adjacent( G ptrg, int x, int y );                   //判断图中是否存在顶点x到顶点y的边,存在返回1,不存在返回0
void Neighbors( G ptrg, int x );                        //返回图中与顶点x邻接的所有边
int InsertVertex( G ptrg, int x );                      //在图中插入顶点x,插入成功返回1,否则返回0
int DeleteVertex( G ptrg, int x );                      //从图中删除顶点x,删除成功返回1,否则返回0
int AddEdge( G ptrg, int x, int y );                    //如果图中从x到y之间没有边,那就添加该边,添加成功返回1,否则返回0
int RemoveEdge( G ptrg, int x, int y );                 //如果图中从x到y之间有边,那就删除该边,删除成功返回1,否则返回0
int FirstNerghbor( G ptrg, int x );                     //返回图中顶点x的第一个邻接点的顶点号,若没找到,返回-1
int NextNeighbour( G ptrg, int x, int y );              //返回图中顶点x除邻接点y之外的第一个邻接点,若y是x的最后一个邻接点,返回-1
int GetEdgeValue( G ptrg, int x, int y );               //返回顶点x与y之间的边的权值
void SetEdgeValue( G ptrg, int x, int y, int value );   //设置图中顶点x和y之间的边的权值为value  

相关实现(以邻接矩阵表示法存储):

以后来补,之后比较长的代码实现先不写了,等之后第二遍理解深刻一些再来做,否则一轮进度赶不上了,要赶在暑假前把408一轮完成,加油!

猜你喜欢

转载自blog.csdn.net/qq_40344308/article/details/89452716
今日推荐