领接表设计实现
# 邻接表(Adjacency List)详细解析
1. 核心设计思路¶
基本概念¶
邻接表是一种图的存储结构,其核心思想是**为每个顶点维护一个链表(或动态数组),存储所有与该顶点直接相连的邻接顶点**。
设计哲学¶
- 空间效率优先:只为实际存在的边分配存储空间
- 局部性原理:将每个顶点的邻接关系集中存储,便于快速访问
- 动态适应性:天然支持动态添加/删除边操作
2. 架构设计¶
2.1 基础架构¶
graph TB
subgraph "邻接表整体结构"
Graph[图 Graph]
V[顶点数量 V]
E[边数量 E]
AdjArray[邻接表数组 adj]
Graph --> V
Graph --> E
Graph --> AdjArray
end
subgraph "邻接表数组 adj"
A0[顶点 0]
A1[顶点 1]
A2[顶点 2]
A3[...]
A4[顶点 V-1]
AdjArray --> A0
AdjArray --> A1
AdjArray --> A2
AdjArray --> A3
AdjArray --> A4
end
subgraph "顶点0的邻接链表"
N00[邻接节点 A]
N01[邻接节点 B]
N02[邻接节点 C]
A0 --> N00
N00 --> N01
N01 --> N02
N02 --> NULL0[NULL]
end
subgraph "顶点1的邻接链表"
N10[邻接节点 D]
N11[邻接节点 E]
A1 --> N10
N10 --> N11
N11 --> NULL1[NULL]
end
subgraph "顶点V-1的邻接链表"
N40[邻接节点 X]
N41[邻接节点 Y]
A4 --> N40
N40 --> N41
N41 --> NULL4[NULL]
end
style Graph fill:#e1f5fe
style AdjArray fill:#f3e5f5
style A0 fill:#fff3e0
style A1 fill:#fff3e0
style A4 fill:#fff3e0
2.2 详细数据结构¶
| C++ | |
|---|---|
classDiagram
class Graph {
-int V
-int E
-vector~vector~int~~ adj
+addEdge(int u, int v)
+removeEdge(int u, int v)
+hasEdge(int u, int v) bool
+getNeighbors(int v) vector~int~
+getDegree(int v) int
+bfs(int start, function~void(int)~ visit)
+dfs(int start, function~void(int)~ visit)
}
class Vertex {
-int id
-vector~int~ neighbors
+addNeighbor(int v)
+removeNeighbor(int v)
+hasNeighbor(int v) bool
+getNeighbors() vector~int~
}
class Edge {
-int source
-int destination
-int weight
+getSource() int
+getDestination() int
+getWeight() int
}
class GraphInterface {
<<interface>>
+addEdge(int u, int v)*
+removeEdge(int u, int v)*
+hasEdge(int u, int v) bool*
+getNeighbors(int v) vector~int~*
+getDegree(int v) int*
}
class WeightedGraph {
-vector~vector~pair~int, int~~ adj
+addEdge(int u, int v, int weight)
+getWeight(int u, int v) int
}
GraphInterface <|.. Graph
GraphInterface <|.. WeightedGraph
Graph *-- Vertex : contains
Graph *-- Edge : contains
Vertex o-- Edge : connected through
无向图的邻接表的实例如下图所示

有向图的邻接表的实例如下图所示

3. 特性分析¶
3.1 优势特性¶
- 空间高效:O(V + E)空间复杂度
- 快速邻接遍历:O(deg(v))时间遍历顶点v的所有邻居
- 动态操作友好:支持边的动态添加和删除
- 缓存友好:连续存储邻接关系,提高缓存命中率
3.2 局限性¶
- 边查询慢:判断边(u,v)存在性需要O(deg(u))时间
- 删除顶点复杂:删除顶点需要更新所有相关链表
- 存储开销:链表指针带来的额外空间开销
4. 主要接口设计¶
4.1 核心操作接口¶
接口¶
邻接表操作流程图¶
flowchart TD
Start([开始]) --> Init[初始化图结构]
Init --> Menu{选择操作}
Menu --> AddEdge[添加边]
Menu --> RemoveEdge[删除边]
Menu --> QueryEdge[查询边]
Menu --> Traverse[遍历图]
Menu --> End([结束])
subgraph AddEdgeFlow [添加边流程]
AE1[接收顶点u, v] --> AE2[验证顶点有效性]
AE2 --> AE3{边是否存在?}
AE3 -->|否| AE4[在adj[u]中添加v]
AE4 --> AE5[在adj[v]中添加u<br>无向图]
AE5 --> AE6[边计数E++]
AE3 -->|是| AE7[返回错误或忽略]
AE6 --> AEResult[返回成功]
AE7 --> AEResult
end
subgraph RemoveEdgeFlow [删除边流程]
RE1[接收顶点u, v] --> RE2[验证顶点有效性]
RE2 --> RE3{边是否存在?}
RE3 -->|是| RE4[从adj[u]中删除v]
RE4 --> RE5[从adj[v]中删除u<br>无向图]
RE5 --> RE6[边计数E--]
RE3 -->|否| RE7[返回错误]
RE6 --> REResult[返回成功]
RE7 --> REResult
end
subgraph QueryEdgeFlow [查询边流程]
QE1[接收顶点u, v] --> QE2[验证顶点有效性]
QE2 --> QE3[遍历adj[u]查找v]
QE3 --> QE4{找到v?}
QE4 -->|是| QE5[返回true]
QE4 -->|否| QE6[返回false]
end
subgraph TraverseFlow [遍历图流程]
T1[选择遍历算法] --> T2{BFS 或 DFS?}
T2 -->|BFS| T3[初始化队列和访问标记]
T3 --> T4[从起始顶点开始]
T4 --> T5[处理当前顶点]
T5 --> T6[将未访问邻居入队]
T6 --> T7{队列为空?}
T7 -->|否| T8[出队下一个顶点]
T8 --> T5
T7 -->|是| T9[遍历完成]
T2 -->|DFS| T10[初始化栈和访问标记]
T10 --> T11[从起始顶点开始]
T11 --> T12[处理当前顶点]
T12 --> T13[将未访问邻居入栈]
T13 --> T14{栈为空?}
T14 -->|否| T15[出栈下一个顶点]
T15 --> T12
T14 -->|是| T16[遍历完成]
end
AddEdge --> AddEdgeFlow
RemoveEdge --> RemoveEdgeFlow
QueryEdge --> QueryEdgeFlow
Traverse --> TraverseFlow
AddEdgeFlow --> Menu
RemoveEdgeFlow --> Menu
QueryEdgeFlow --> Menu
TraverseFlow --> Menu
4.2 完整实现示例¶
| C++ | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | |
5. 性能分析¶
5.1 时间复杂度¶
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 添加边 | O(1) | 在链表/向量末尾添加 |
| 删除边 | O(deg(u)) | 需要遍历u的邻接表 |
| 查询边 | O(deg(u)) | 需要遍历u的邻接表 |
| 遍历邻居 | O(deg(v)) | 直接访问邻接表 |
| 空间复杂度 | O(V + E) | 顶点数 + 边数 |
5.2 空间复杂度分析¶
- 基础存储:V个顶点,每个顶点存储一个链表头指针
- 边存储:每条边在对应两个顶点的链表中各存储一次(无向图)
- 总空间:\(O(V + 2E) ≈ O(V + E)\)
6. 扩展方向¶
6.1 性能优化扩展¶
6.2 功能扩展¶
7. 使用场景建议¶
7.1 推荐使用场景¶
- 稀疏图\((E << V²)\)
- **需要频繁遍历邻居**的算法(BFS、DFS、Dijkstra等)
- 动态图(频繁添加/删除边)
- **内存敏感**的应用场景
7.2 不推荐使用场景¶
- 稠密图(E ≈ V²)
- **需要频繁查询边存在性**的应用
- **固定图结构**且需要极致性能的场景
8. 应用实例:社交网络分析¶
8.1 问题描述¶
构建一个社交网络图,分析用户之间的关系,实现好友推荐功能。
8.2 应用架构图¶
graph TB
subgraph "社交网络应用层"
SN[社交网络 SocialNetwork]
UI[用户界面]
ALG[分析算法]
UI --> SN
SN --> ALG
end
subgraph "数据存储层"
US[用户存储 users]
IDX[ID索引映射 idToIndex]
SN --> US
SN --> IDX
end
subgraph "用户数据结构"
UD[用户 User]
UID[用户ID id]
UNAME[用户名 name]
UFRIENDS[好友列表 friends]
UD --> UID
UD --> UNAME
UD --> UFRIENDS
US --> UD
end
subgraph "核心功能模块"
AM[账户管理]
FM[好友管理]
RA[关系分析]
REC[推荐系统]
SN --> AM
SN --> FM
SN --> RA
SN --> REC
end
subgraph "具体操作"
AM1[添加用户 addUser]
AM2[删除用户 removeUser]
FM1[添加好友 addFriendship]
FM2[删除好友 removeFriendship]
FM3[获取好友 getFriends]
RA1[共同好友 getMutualFriends]
RA2[分离度数 getDegreeOfSeparation]
RA3[连通性检查 isConnected]
REC1[好友推荐 recommendFriends]
REC2[兴趣匹配 interestMatch]
AM --> AM1
AM --> AM2
FM --> FM1
FM --> FM2
FM --> FM3
RA --> RA1
RA --> RA2
RA --> RA3
REC --> REC1
REC --> REC2
end
style SN fill:#e8f5e8
style UD fill:#fff3e0
style AM fill:#e3f2fd
style FM fill:#e3f2fd
style RA fill:#e3f2fd
style REC fill:#e3f2fd
8.3 完整实现¶
| C++ | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | |
8.4 实例分析¶
这个社交网络应用展示了邻接表的优势:
- 高效遍历:快速获取用户的好友列表
- 动态更新:轻松添加新的好友关系
- 复杂查询:支持共同好友、好友推荐等复杂分析
- 路径查找:基于BFS的最短路径查找
邻接表在这个场景中完美匹配了需求,因为社交网络通常是稀疏的,且需要频繁进行基于邻居的查询和分析操作。
总结¶
邻接表作为图存储的核心数据结构,在空间效率和遍历性能方面表现出色,特别适合处理稀疏图和需要频繁进行局部操作的场景。通过合理的扩展和优化,它可以满足各种复杂图算法的需求。