持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情
图的邻接表(adjacency list)存储方法是一种顺序分配与链式分配相结合的存储方法 。它包括两个组成部分,其中一个部分是链表,用来存放边的信息﹐另一个部分是一个数组,主要用来存放顶点的数据信息。
在这种存储方法中,对于图中的每一个顶点分别建立一个线性链表,这样,对具有n个顶点的图而言,其邻接表结构由n个线性链表组成。每个链表前面设置一个头结点,称之为顶点结点。每个顶点结点由两个域组成,如图8.9所示。其中,顶点域(vertex)用来存放某个顶点的数据信息;指针域(link)指出依附于该顶点的第1条边所对应的链结点的地址。 为了方便随机访问任意一个顶点的链表,通常情况下,n个顶点结点以顺序存储结构的形式存储,构成一个数组结构,并用该数组的下标代表顶点在图中的位置。
邻接表的第i个链表中的每一个链结点称之为边结点(也称表结点),它表示依附于第i个顶点的一边条(对有向图而言,是以顶点i为始点(弧尾)的一条边),其链结点构造如图8.10所示。其中, adjvex域存放该边的另一端顶点在顶点数组中的位置(序号),对于有向图,存放的是该边的终点(弧头)在顶点数组中的位置; weight域存放一条边的权值,若图不是网络,则边结点中无此域;next域为指针域,指出与顶点i邻接的下一条边所对应的边结点的位置,即通过next域将第i个链表中的所有边结点链接成一个线性链表,最后那个边结点的指针域存放NULL。
例如,对于图8.1所示的无向图G1和有向图G2以及图8.8所示的网络,其邻接表表示分别如图8.11(a),(b),(c)所示。
邻接表结构中的边结点与顶点结点的类型可以分别描述如下。
如果无向图有n个顶点,e条边,则其邻接表需要n个顶点结点和2e个边结点。在总的边数小于n(n-1)/4的情况下,采用邻接表结构比采用邻接矩阵结构要节省空间。 另外,在无向图的邻接表中,第i个链表中的边结点数目正好是第i个顶点的度;在有向图的邻接表中求顶点的出度比较方便,因为第i个链表的边结点数目正好是第i个顶点的出度。但求顶点的入度则相对比较麻烦,而在一些实际应用中,有时的确需要知道顶点的入度,解决的办法之一是扫描邻接表,统计adjvex域中值为i的边结点数目,得到顶点i的入度,这是很费时的。更有效的方法是建立一个称之为逆邻接表的结构。也就是说,按照建立邻接表的基本思想,对于有向图中每一个顶点,建立以该顶点为终点(弧头)的一个链表,即把所有以该顶点为终止顶点的边结点链接为一个线性链表。
无向图的邻接表中边结点的数目一定为偶数;而邻接表中边结点的数目为奇数的图一定为有向图。
在邻接表结构中,要找到任意一个顶点的邻接点比较容易,但要确定任意两个顶点(如顶点vi和顶点vj)之间是否存在边或者弧,则需要遍历第i个或者第j个链表,这一点不如邻接矩阵方便。
需要注意的是,给定一个图,其对应的邻接表(或逆邻接表)结构不一定是唯一的,因为图中所有顶点的数据信息可以按照任意次序存放于顶点结点中;另外,在每一个顶点对应的链表中,边结点的链接次序也可以是任意的,链接次序与边的输入次序以及相关算法有关。