图的存储结构

图的存储结构

在这里插入图片描述

邻接矩阵

用两个数组分别存储数据元素(顶点)的信息和数据元素之间的关系(边或弧)的信息。其形式描述如下:

//图的数组(邻接矩阵)存储表示
#define INFINITY INT_MAX	//最大值∞
#define MAX_VERTEX_NUM 		//最大顶点个数
typedef enum { DG,NG,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;

借助于邻接矩阵容易判定任意两个顶点之间是否有边(或弧)相连,并容易求得各个顶点的度。对于无向图,顶点 v i v_i vi的度是邻接矩阵中第 i i i行(或第 j j j列)的元素之和。

对于有向图,第 i i i行的元素之和为顶点 v i v_i vi的出度 O D ( v i ) OD(v_i) OD(vi),第 j j j的元素之和为顶点 v j v_j vj的入读 I D ( v j ) ID(v_j) ID(vj)

网的邻接矩阵可定义为

在这里插入图片描述

例如,图里列出了一个有向网和它的邻接矩阵。

在这里插入图片描述

邻接表

邻接表是图的一种链式存储结构在邻接表中,对图中的每个节点建立一个单链表,第 i i i个单链表中的节点表示依附于顶点 v i v_i vi的边(对有向图是以顶点 v i v_i vi为尾的弧)每个节点由3个域组成,其中邻接点域表示与顶点 v i v_i vi邻接的点在图中的位置,链域表示下一条边或弧的节点;数据域存储和边或弧相关的信息,例如权值等每个链表上附设一个表头结点,在表头节点中,除了设有链域指向链表的第一个结点之外,还设有存储顶点 v i v_i vi的名或其他有关信息的数据域

如下图所示

在这里插入图片描述

这些表头节点通常以顺序结构的形式存储,以便随机访问任一顶点的链表。

一个图的邻接表存储结构可形式地说明如下

//图的邻接表存储表示
#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;

若无向图中有 n n n个顶点, e e e条边,则它的邻接表需要 n n n个头节点和 2 e 2e 2e的表节点。显然,在边稀疏的情况下,用邻接表表示图比邻接矩阵节省存储空间,当和边相关的信息较多时更是如此

在无向图的邻接表中,顶点 v i v_i vi的度恰好为第 i i i个链表中的节点数;而在有向图中,第 i i i个链表中的节点个数只是顶点 v i v_i vi的出度,为求入度,必须遍历整个邻接表。在所有链表中其临界点域的值为 i i i的节点的个数是顶点 v i v_i vi的入度。有时,为了便于确定顶点的入度或以顶点 v i v_i vi为头的弧,可以建立一个有向图的逆邻接表,即对每个顶点 v i v_i vi建立一个链接以 v i v_i vi为头的弧的表。如图C所示为有向图 G 1 G_1 G1的逆邻接表。

在建立邻接表或逆邻接表时,若输入的顶点信息即为顶点的编号,则建立邻接表的时间复杂度为 O ( n + e ) O(n+e) O(n+e),否则,需要通过查找才能得到顶点在图中位置,则时间复杂度为 O ( n ∗ e ) O(n*e) O(ne)

在邻接表上容易找到任一顶点的第一个邻接点和下一个邻接点,但是要判断任意两个顶点( v i v_i vi v j v_j vj)之间是否有边或弧相连,则需要搜索第 i i i个或第 j j j个链表,因此没有邻接矩阵方便
在这里插入图片描述

十字链表

十字链表是有向图的另一种链式存储结构。可以看成是将有向图的邻接表和逆邻接表结合起来得到的一种链表。在十字链表中,对应于有向图中每一个弧有一个节点,对应于每个顶点也有一个节点,这些节点的结构如下所示:

在这里插入图片描述

在弧节点中有5个域:其中尾域(tailvex)和头域(headvec)分别指示弧头和弧尾两个顶点在图中的位置,链域hlink指向弧头相同的下一条弧,而链域tlink指向弧尾相同的下一条弧,info指向该弧的相关信息。弧头相同的弧在同一链表上,弧尾相同的弧也在同一条链表上,它们的头节点即为顶点节点。它由3个域组成,其中data域存储和顶点相关的信息,如顶点的名称等。firstin和firstout为两个链域,分别指向以该顶点为弧头或弧尾的第一个弧节点。

若将有向图的邻接矩阵看成是稀疏矩阵的话,则十字链表也可以看成是邻接矩阵的链表存储结构,在图的十字链表中,弧节点所在的链表非循环链表,节点之间相对位置自然形成,不一定按顶点序号有序,它们之间不是链接,而是顺序存储

在十字链表中既容易求得以 v i v_i vi为尾的弧,也容易找到以 v i v_i vi为头的弧,因而容易求得顶点的入度和出度

在这里插入图片描述

邻接多重表

邻接多重表是无向图的另一种链式存储结构。虽然邻接表是无向图的一种很有效的存储结构,在邻接表中容易求得顶点和边的各种信息。但是,在邻接表中每一条边 ( v i , v j ) (v_i,v_j) (vi,vj)有两个结点,分别在第 i i i个和第 j j j个链表中,这个为某些图的操作带来不便。例如在某些图的应用问题中需要对边进行某种操作,如对已被搜索过的边作记号或删除一条边等,此时需要找到表示同一条边的两个结点。因此,在进行这一类操作的无向图的问题中采用临界多重表作存储结构更为合适。

邻接多重表的结构和十字链表类似。在邻接多重表中,每一条边用一个结点表示,它们由如下所示的6个域组成:

在这里插入图片描述
其中,mark为标志域,可用于标记该条边是否被搜索过;ivexjvex为该边依附的两个顶点在图中的位置;ilink指向下一条依附于顶点ivex的边;jlink指向下一条依附于顶点jvex的边,info为指向和边相关的各种信息的指针域。每一个顶点也用一个结点表示,它由如下所示的两个域组成。

在这里插入图片描述

其中,data域存储和该顶点相关的信息,firstedge域指示第一条依附于该顶点的边。在邻接多重表中,所有依附于同一顶点的边串联在同一链表中,由于每条边依附于两个顶点,则每个边结点同时链接在两个链表中,可见,对无向图而言,其邻接多重表和邻接表的差别,仅仅在于同一条边在邻接表中用两个结点表示,而在邻接多重表中只有一个结点。因此,除了在边结点中增加一个标志域外,邻接多重表所需的存储量和邻接表相同。在邻接多重表中,各种基本操作的实现和邻接表相似。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值