数据结构——邻接表
要解决邻接矩阵对稀疏图“空间浪费”的问题,邻接表采用“数组+链表”的结构,灵活存储顶点间的连接关系。它由顶点表(数组)和边表(链表)组成,能高效适配稀疏图的存储需求,下面分结构、类型及特点展开讲解。
邻接表
邻接表的核心是用“顶点数组 + 邻接链表”的组合,将图的“顶点”与“边/弧”关系拆解为“数组存储顶点,链表存储邻接顶点”,大幅提升稀疏图的空间利用率。
1. 邻接表的结构组成
邻接表由两部分构成:
- 顶点表:是一个数组,每个元素包含“顶点信息”和“边表的头指针”。例如,若顶点含数据
data
,则顶点表元素可表示为{data, firstedge}
,其中firstedge
是边表的头指针。 - 边表:是一个链表,每个结点(边表结点)存储“邻接顶点的下标”“权值”(带权图时)等信息。对于无向图,边表结点还可能存储“边的标识”(因为同一条边会被两个顶点的链表共享)。
2. 有向图的邻接表(结合图6.8分析)
有向图的邻接表中,边表仅存储“出弧”的信息(即从当前顶点出发的弧)。以图6.8“有向图邻接表表示法实例”为例:
- 图6.8(a)是有向图( G ),包含顶点( 1、2、4、5 ),还有孤立点3(无任何弧连接);弧的关系有:( 1 \rightarrow 2 )、( 1 \rightarrow 4 )、( 2 \rightarrow 5 )、( 4 \rightarrow 2 )、( 5 \rightarrow 4 )。
- 图6.8(b)是其邻接表:
- 顶点表是长度为5的数组(对应顶点( 1 )到( 5 )),每个元素的
firstedge
指向边表的头结点; - 边表中,顶点( 1 )的链表包含结点( 2 )、( 4 ),表示“顶点( 1 )有出弧指向( 2 )和( 4 )”;
- 顶点( 2 )的链表包含结点( 5 ),表示“顶点( 2 )有出弧指向( 5 )”;
- 顶点( 3 )的链表为空,表示“顶点( 3 )无出弧,是孤立点”;
- 顶点( 4 )的链表包含结点( 2 ),表示“顶点( 4 )有出弧指向( 2 )”;
- 顶点( 5 )的链表包含结点( 4 ),表示“顶点( 5 )有出弧指向( 4 )”。
- 顶点表是长度为5的数组(对应顶点( 1 )到( 5 )),每个元素的
这种结构下,顶点的出度可直接通过“边表链表的长度”得到(如顶点( 1 )的出度为2,顶点( 2 )的出度为1);要找某顶点的所有邻接顶点(即出弧指向的顶点),只需遍历其边表链表即可。
3. 无向图的邻接表
无向图的邻接表中,同一条边会被两个顶点的边表各存储一次(因为无向边( (v_i, v_j) )等价于( v_i )到( v_j )和( v_j )到( v_i )的两条弧)。例如,若无向图有边( (1, 2) ),则顶点( 1 )的边表会存( 2 ),顶点( 2 )的边表也会存( 1 )。
此时,顶点的度等于其边表链表的长度(因为每条边会在两个顶点的链表中各出现一次,所以长度之和是边数的2倍)。
4. 邻接表的操作与特点
邻接表的存储方式,决定了其操作效率和空间特性:
(1)操作的时间复杂度
- 判断顶点( v_i )与( v_j )是否相邻:需遍历( v_i )的边表链表,查找是否存在( v_j )的结点,时间复杂度为( O(d_i) )(( d_i )是顶点( v_i )的度或出度);
- 遍历顶点( v_i )的所有邻接顶点:只需遍历其边表链表,时间复杂度为( O(d_i) );
- 增删边/弧:只需在对应顶点的边表链表中增删结点,时间复杂度为( O(1) )(找到位置后)。
(2)空间复杂度
邻接表的空间复杂度为( O(n + e) )(( n )是顶点数,( e )是边数)。对于稀疏图(( e \ll n^2 )),这比邻接矩阵的( O(n^2) )高效得多;但对于稠密图,两者空间效率差异不大。
5. 邻接表的优缺点
- 优点:
- 空间利用率高:稀疏图中仅存储实际存在的边/弧,避免邻接矩阵的大量“0”或“∞”浪费;
- 遍历邻接顶点便捷:找某顶点的所有邻接顶点,只需遍历其边表链表,逻辑清晰。
- 缺点:
- 判断两顶点是否相邻的效率低于邻接矩阵(需遍历链表,而邻接矩阵可直接访问);
- 无向图中同一条边会存储两次(但这是为了“空间换时间”,保证遍历邻接顶点的效率)。
6. 邻接矩阵与邻接表的对比
存储方式 | 空间复杂度 | 相邻判断效率 | 邻接顶点遍历效率 | 适用场景 |
---|---|---|---|---|
邻接矩阵 | ( O(n^2) ) | ( O(1) ) | ( O(n) ) | 稠密图、需频繁判断相邻 |
邻接表 | ( O(n + e) ) | ( O(d_i) ) | ( O(d_i) ) | 稀疏图、需频繁遍历邻接顶点 |
综上,邻接表通过“数组+链表”的结构,在稀疏图场景下大幅优化了空间利用率,同时保持了“遍历邻接顶点”的高效性,是图存储的核心方式之一。结合图6.8的有向图实例,能更直观地理解“顶点-边表”的关联逻辑,为后续图的遍历、应用奠定了存储基础。