“这是我参与8月更文挑战的第30天,活动详情查看:8月更文挑战”
关注我,以下内容持续更新
前面的文章介绍了几种图的存储方式邻接矩阵、邻接表和十字链表,本篇接续介绍图的另外一种存储方式:邻接多重表
邻接多重表(针对无向图邻接链表的优化)
首先明确两点:
a)无向图的邻接表结构
在无向图的邻接表中可以看到,每一条边(vi,vj)在邻接表中有两个边结点:一个在顶点vi的边链表中,表示(vi,vj);一个在顶点vj的边链表中,表示(vj,vi)。如果需要给被处理的边加标记(如访问标志或删除标志等),则需要同时给表示某一条边的两个边结点加标记,而这两个结点又不在同一个边链表中,所以需要对两个顶点的边表进行遍历,效率较低。邻接多重表可以简化这种操作,邻接多重表是针对无向图的邻接表的优化,可看作是邻接表和十字链表的结合。 邻接多重表与邻接表的区别在于:同一条边在邻接表中用一个结点表示。而在邻接多重表中用两个结点表示。此外,邻接多重表中增加了标志域用以标记该条边是否被搜索过,避免了同一条边的重复搜索。邻接多重表请看下图图示
b)无向图的邻接多重表结构
邻接多重表由顶点表结点VertexNode和边表结点EdgeNode两种结点构成。
- 顶点表结点VertexNode由data和firstedge构成。
- data:数据域,存储有关顶点的数据信息。
- firstedge:边表头指针,指向依附于该顶点的边表。
- 边表结点EdgeNode由ivex、jvex、ilink、jlink、mark构成。
- ivex、jvex: 与某条边依附的两个顶点在顶点表中的下标;
- ilink:指针域,指向依附于顶点ivex的下一条边;
- jlink:指针域,指向依附于顶点jvex的下一条边;
- mark:标志域,用于标记此结点点是否被操作过,mark域为0表示未被操作;mark为1表示该节点已被操作。
- weight:信息域,用于存储边的权值(非网图不需要)
//顶点结点
typedef struct VertexNode{
int data;
EdgeNode* firstedge;
};
//边表结点
typedef struct EdgeNode{
int mark;
int ivex;
EdgeNode* ilink;
int jvex;
EdgeNode* jlink;
int weight;
};
图的各种存储结构的对比
至此为止,图的4种存储结构已经讲完了,最后总结下各种存储结构的特点和适应场景
- 邻接矩阵:可以存储无向图,也可存储有向图。构造一个具有n个顶点和e条边的无向图的时间复杂度O(n*n+e*n),邻接矩阵的初始化消耗了O(n*n)的时间。
- 邻接表:链式存储结构。可以存储无向图和有向图,有向图可以建立“逆邻接表”。构造邻接表或者“逆邻接表”时间复杂度O(n+e),n个顶点+e条边。邻接表相对于邻接矩阵如果是边稀疏图的话比较节约空间。但是邻接表要确定vi和vj是否有边的时候没有邻接矩阵方便。
- 十字链表:有向图的另一种链式存储。在十字链表中容易找到以顶点vi为起点的弧,也容易找到以顶点vi为终点的弧,因而容易求得顶点的出度和入度。
- 邻接多重表:无向图的另一种链式存储。方便于边的搜索和边的删除。
关注我
如果觉得我写的不错,请点个赞 关注我 您的支持是我更文最大的动力!