图的存储结构
最近在学习图的存储方式,目的是找到一便于更改图中数据的存储结构(包括增加/删除节点和边)。
顺序存储结构(最简单)
用两个数组,一个一维数组用来存所有的顶点,一个二位数组用来表示点之间的连接关系。
无向图的连接关系数组是一个对称数组,实际存储时可以使用上三角矩阵或下三角矩阵来节约空间。
有向图的连接关系数组通常用纵坐标代表边的起点,横坐标代表重点。比如。
这种方式不好更改,且不适用于稀疏矩阵的存储,连接关系数组中大量的数据都是0,表示null.
链表
网上查到的关于链表存储图结构的方法中,其基础都是先用一个数组记录所有的顶点,(通常也会使用顶点在数组中的位置来做顶点的ID)。而后为每个顶点,都建立一个链表。该链表的首节点表示对应的顶点v(vertex),首节点后所有的节点都表示与该该顶点v相连的其他顶点。
或者这样说更好理解:
每个顶点v中都指向了一个链表,这个链表中的每一个节点,都表示与v有连接关系的某一个顶点。
邻接链表
为每一个顶点建立一个链表,以顶点v1为例,链表以该顶点v1为头节点,其余节点都是以v1为起点的下一个节点。这种方式更适用于无向图,因为无向图上顶点的入度和出度相等,只要统计某顶点对应的链表上有多少节点即可知道其入度和出度。
有向图就略显复杂,因为统计顶点对应链表上节点数量只能得出出度,得不到入度。也不容易通过顶点去反向查找其上一个顶点。通常会再建立一个逆邻接表,用来存储每一个顶点与其入边起点的关系。
十字链表
首先通常会有一个数组存储所有的顶点,顶点在数组中的位置通常当作该顶点的ID。
十字链表有些复杂,链表中首节点的存储方式与其他节点不同。从首节点开始,可以向后找到两条链表。
首节点中的基本元素有三个:
1) 顶点本身的数据,比如id,名字啥的
2) 指向【该顶点所有入边的起点组成的】链表。(该顶点做终点)
3) 指向【该顶点所有出边的终点组成的】链表。(该顶点做起点)
即:
2)中的链表中,除了首节点以外,链表上其余所有的节点都是首节点的下一个顶点。
3)中的链表中,除了首节点以外,链表上其余所有的节点都是首节点的上一个顶点。
两个链表中节点的先后位置没有次序。
十字链表中,首节点以外的每一个节点,都可以理解为一个边的表示。
链表中非首节点的其余节点的存储结构包含五个基本元素:
1)该链表首节点的ID,即在数组中的位置。即该边的起点。
2)该节点所代表的顶点的ID,即首节点的下一个顶点的ID。即该边的终点。
3)指向下一个与2)中ID相同的节点。即与该边终点相同的另一个边(或者说表示该边的节点)
4)指向下一个与1)中ID相同的节点。即与该边起点相同的另一个边(或者说表示该边的节点)
5)边的基本信息。
也就是,每一个节点都存在与两条链表之中。一条链表记录某顶点所有的出边,另一条链表记录某顶点所有的入边。
邻接多重表:
邻接多重表只用来存储 无向图。
与上述链表类似,用一个数组存储所有的顶点。每个顶点都指向一个链表。
每个链表的首节点都表示一个顶点。其余节点的数据结构与十字链表相同。
每个这样的节点都表示一个边
1)mark和info可以归为一类。
2)ivex表示边的起点
3)ilink表示下一个与ivex相连的边
4)jvex表示边的终点
5)jlink表示下一个与jvex相连的边