我们知道图的存储结构有邻接矩阵存储方法和邻接表存储方法,而对于邻接矩阵我们已经学习过了,本篇将主要介绍图的邻接表存储结构。
图1-图的邻接表存储结构
1. 邻接表存储带权有向图
图2-邻接表存储有向图
邻接表存储方法是对图中每个顶点i建立一个单链表,将顶点i的所有邻接点链接起来,然后再给每个单链表上附设一个表头节点(表示顶点信息),将所有表头节点构成一个数组(顺序表),下标为i的元素表示顶点i的表头节点,因此不难看出单链表中的每个节点代表着一条边,我们称之为边节点
。
2. 邻接表的存储结构
从邻接表存储方法我们可知,图的邻接表存储方法是一种顺序分配和链式分配
相结合的存储方法。而且邻接表中有两类节点:表头节点和单链表中的边节点。
如图2所示,在表头节点中的data域表示每个顶点的信息,firstarc域用于指向单链表的第一个边节点(即相关联的邻接点),而单链表中的每个边节点又包括了adjvex域,nextar域,info域。
adjvex域用于存储某顶点的邻接点,而nextar域则用于指向单链表中的下一个边节点,而info域则用于存储边节点信息,如权值。
由以上这些信息,我们可以定义邻接表存储结构,如下所示:
typedef struct ANode
{
int adjvex; //记录某顶点的邻接点
struct ANode *nextarc; //指向下一条边节点的指针
InfoType info; //记录边的权值等信息
} ArcNode; //边表节点类型
typedef struct Vnode
{
Vertex data; //存储顶点的信息
ArcNode *firstarc; //指向第一个边节点
} VNode; //表头节点类型
typedef VNode AdjList[MAXV];
typedef struct
{
AdjList adjlist; //邻接表,这其实是一个数组(顺序表)
int n,e; //记录顶点个数n,边数e
} ALGraph; //完整的图邻接表类型
3. 邻接表存储无权图
图3-邻接表存储无权图
我们可以看到邻接表存储无权图有一些区别,比如对于单链表的边节点的存储结构来说,由于是无权图,边节点的存储结构少了info域,那么定义如下所示:
typedef struct ANode
{
int adjvex; //记录某顶点的邻接点
struct ANode *nextarc; //指向下一条边节点的指针
} ArcNode; //边表节点类型
4. 邻接表的特点
1.邻接表表示不唯一,也就是说,在每个顶点对应的单链表中,各边节点的链接次序可以是任意的。
比如顶点0对应的单链表中各边节点链接次序
可以是顶点1,顶点3,顶点4,;也可以是顶点3,顶点1,顶点4。各个节点的链接次序可以是随意的。
2. 邻接表适合存储稀疏图,边数越大,存储空间也越大,而稀疏图的边很少,存储起来则更加节省空间。
3. 对于无向图,邻接表的顶点i对应的第i个链表的边节点数目正好是顶点i的度。
4. 对于有向图,邻接表的顶点i对应的第i个链表的边节点数目仅仅是顶点i的出度;其入度为邻接表中所有adjvex域值为i的边节点数目,必须查找邻接表中的所有顶点,而这个过程是非常耗时的。
总结:
我们在学习数据结构时,会学到非常多的,各种各样的数据结构,而对于这些不同的数据结构,我们要根据合适的应用场景,选择合适的数据结构,这是我们需要掌握的一种非常重要的能力。
来源:CSDN
作者:songly_
链接:https://blog.csdn.net/qq_35733751/article/details/81088378