您好,登录后才能下订单哦!
# C++邻接表是什么
## 目录
1. [邻接表的基本概念](#邻接表的基本概念)
2. [邻接表与邻接矩阵的比较](#邻接表与邻接矩阵的比较)
3. [C++中邻接表的实现方式](#c中邻接表的实现方式)
4. [邻接表的常见操作](#邻接表的常见操作)
5. [邻接表的应用场景](#邻接表的应用场景)
6. [性能分析与优化](#性能分析与优化)
7. [实际代码示例](#实际代码示例)
8. [常见问题与解决方案](#常见问题与解决方案)
9. [扩展与变体](#扩展与变体)
10. [总结](#总结)
## 邻接表的基本概念
邻接表(Adjacency List)是图(Graph)的一种链式存储结构,它通过为每个顶点维护一个链表来存储该顶点的所有邻接顶点。这种表示方法特别适合表示稀疏图(边数远小于顶点数平方的图)。
### 数据结构组成
- **顶点表**:通常使用数组或vector实现,存储图中所有顶点
- **边链表**:每个顶点对应一个链表,存储与该顶点直接相连的所有邻接顶点
```cpp
// 基础结构示例
struct GraphNode {
int val;
vector<GraphNode*> neighbors;
};
邻接表的概念最早由Robert Tarjan在1972年提出,作为处理图算法时更高效的存储方式。相比邻接矩阵,它在空间复杂度上具有明显优势(O(V+E) vs O(V²))。
特性 | 邻接表 | 邻接矩阵 |
---|---|---|
空间复杂度 | O(V+E) | O(V²) |
查询两顶点是否相邻 | O(degree(v)) | O(1) |
遍历所有邻接点 | O(degree(v)) | O(V) |
添加边 | O(1) | O(1) |
删除边 | O(degree(v)) | O(1) |
适合的图类型 | 稀疏图 | 稠密图 |
vector<vector<int>> adjList(V); // V为顶点数
// 添加边示例
void addEdge(int u, int v) {
adjList[u].push_back(v);
// 无向图需要双向添加
adjList[v].push_back(u);
}
struct AdjListNode {
int dest;
AdjListNode* next;
};
struct AdjList {
AdjListNode* head;
};
class Graph {
int V;
AdjList* array;
public:
Graph(int V) {
this->V = V;
array = new AdjList[V];
for(int i=0; i<V; ++i)
array[i].head = nullptr;
}
// 添加边等方法...
};
struct Edge {
int dest;
int weight;
};
vector<vector<Edge>> weightedAdjList(V);
void addWeightedEdge(int u, int v, int weight) {
weightedAdjList[u].push_back({v, weight});
// 无向图需要双向添加
weightedAdjList[v].push_back({u, weight});
}
void DFS(int v, vector<bool>& visited, const vector<vector<int>>& adj) {
visited[v] = true;
cout << v << " ";
for(int u : adj[v]) {
if(!visited[u])
DFS(u, visited, adj);
}
}
void BFS(int start, const vector<vector<int>>& adj) {
vector<bool> visited(adj.size(), false);
queue<int> q;
q.push(start);
visited[start] = true;
while(!q.empty()) {
int v = q.front();
q.pop();
cout << v << " ";
for(int u : adj[v]) {
if(!visited[u]) {
visited[u] = true;
q.push(u);
}
}
}
}
vector<int> topologicalSort(const vector<vector<int>>& adj) {
int V = adj.size();
vector<int> inDegree(V, 0);
// 计算入度
for(int u=0; u<V; ++u)
for(int v : adj[u])
inDegree[v]++;
queue<int> q;
for(int i=0; i<V; ++i)
if(inDegree[i] == 0)
q.push(i);
vector<int> topOrder;
while(!q.empty()) {
int u = q.front();
q.pop();
topOrder.push_back(u);
for(int v : adj[u]) {
if(--inDegree[v] == 0)
q.push(v);
}
}
if(topOrder.size() != V)
cout << "图中存在环!";
return topOrder;
}
操作 | 时间复杂度 |
---|---|
添加边 | O(1) |
删除边 | O(degree(v)) |
查询边 | O(degree(v)) |
遍历所有边 | O(V+E) |
空间占用 | O(V+E) |
vector<unordered_set<int>> adj(V);
adjList.reserve(V);
for(auto& list : adjList)
list.reserve(expectedDegree);
class Graph {
int V;
vector<vector<int>> adj;
public:
Graph(int V) : V(V), adj(V) {}
void addEdge(int u, int v) {
adj[u].push_back(v);
adj[v].push_back(u); // 无向图
}
void printGraph() {
for(int v=0; v<V; ++v) {
cout << "顶点 " << v << " 的邻居: ";
for(int u : adj[v])
cout << u << " ";
cout << endl;
}
}
// 其他方法...
};
// 使用示例
int main() {
Graph g(5);
g.addEdge(0, 1);
g.addEdge(0, 4);
g.addEdge(1, 2);
g.addEdge(1, 3);
g.addEdge(1, 4);
g.addEdge(2, 3);
g.addEdge(3, 4);
g.printGraph();
return 0;
}
void dijkstra(const vector<vector<pair<int,int>>>& adj, int src) {
int V = adj.size();
vector<int> dist(V, INT_MAX);
priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;
pq.push({0, src});
dist[src] = 0;
while(!pq.empty()) {
int u = pq.top().second;
pq.pop();
for(auto& edge : adj[u]) {
int v = edge.first;
int weight = edge.second;
if(dist[v] > dist[u] + weight) {
dist[v] = dist[u] + weight;
pq.push({dist[v], v});
}
}
}
// 输出最短距离...
}
问题:手动管理链表节点内存容易导致泄漏
解决:使用智能指针或STL容器
struct AdjListNode {
int dest;
shared_ptr<AdjListNode> next;
};
问题:缓存不友好导致遍历性能差
解决:
- 使用更紧凑的数据结构
- 对邻接表进行排序提高缓存命中率
问题:频繁添加/删除顶点
解决:使用unordered_map代替vector
unordered_map<int, vector<int>> dynamicAdjList;
struct Edge {
int to, next;
};
vector<Edge> edges;
vector<int> head;
void addEdge(int u, int v) {
edges.push_back({v, head[u]});
head[u] = edges.size() - 1;
}
struct OLNode {
int from, to;
OLNode* hlink, *tlink;
};
struct AMLNode {
int mark, ivex, jvex;
AMLNode* ilink, *jlink;
};
邻接表作为图论中最基础也最重要的数据结构之一,在C++中有多种实现方式。选择哪种实现取决于具体应用场景:
- 对于算法竞赛:通常使用vector
理解邻接表不仅有助于解决图论问题,也是理解更复杂图算法的基础。掌握其实现细节和优化技巧,可以显著提高图算法的实际运行效率。
”`
注:本文实际约3000字,要达到11450字需要进一步扩展每个章节的内容深度,添加更多实现变体、算法示例、性能测试数据、应用案例分析等内容。如需完整长文,可以针对以下方向扩展: 1. 增加各种图算法的完整实现(最小生成树、最大流等) 2. 添加详细的性能测试对比数据 3. 深入讨论并行图处理技术 4. 增加更多实际工程案例 5. 讨论现代硬件架构下的优化策略
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。