一、图的基本概念
1.1 图的定义与组成
图(Graph)由顶点(Vertex)和边(Edge)组成,形式化定义为:
G = (V, E)
-
顶点集合 V:表示实体(如城市、用户)
-
边集合 E:表示实体间关系(如道路、社交关系)
1.2 图的分类
类型 | 特点 | 应用场景 |
---|---|---|
无向图 | 边无方向性 | 社交网络 |
有向图 | 边有方向性 | 网页链接 |
加权图 | 边带权值 | 路径规划 |
有环图 | 包含环路 | 状态机 |
连通图 | 所有顶点连通 | 网络拓扑 |
二、图的存储结构
2.1 邻接矩阵
使用二维数组存储顶点间关系
class AdjMatrixGraph {
private:vector<vector<int>> matrix; // 存储边权int vertexCount;public:AdjMatrixGraph(int n) : vertexCount(n), matrix(n, vector<int>(n, 0)) {}void addEdge(int from, int to, int weight = 1) {matrix[from][to] = weight;// 无向图需添加 matrix[to][from] = weight;}void print() {for (auto& row : matrix) {for (int val : row) cout << val << " ";cout << endl;}}
};
特点:
-
空间复杂度 O(V²)
-
适合稠密图
-
快速判断顶点是否邻接
2.2 邻接表
使用链表/数组存储邻接关系
struct EdgeNode {int dest;int weight;EdgeNode* next;
};class AdjListGraph {
private:struct VertexNode {EdgeNode* head = nullptr;};vector<VertexNode> vertices;int vertexCount;public:AdjListGraph(int n) : vertexCount(n), vertices(n) {}void addEdge(int from, int to, int weight = 1) {EdgeNode* newNode = new EdgeNode{to, weight, vertices[from].head};vertices[from].head = newNode;}~AdjListGraph() {for (auto& v : vertices) {while (v.head) {EdgeNode* temp = v.head;v.head = v.head->next;delete temp;}}}
};
特点:
-
空间复杂度 O(V + E)
-
适合稀疏图
-
高效遍历邻接顶点
三、图的遍历算法
3.1 深度优先搜索(DFS)
void dfs(const AdjListGraph& graph, int v, vector<bool>& visited) {visited[v] = true;cout << "Visit: " << v << endl;EdgeNode* curr = graph.getEdges(v);while (curr) {if (!visited[curr->dest]) {dfs(graph, curr->dest, visited);}curr = curr->next;}
}
3.2 广度优先搜索(BFS)
void bfs(const AdjListGraph& graph, int start) {vector<bool> visited(graph.size(), false);queue<int> q;visited[start] = true;q.push(start);while (!q.empty()) {int v = q.front();q.pop();cout << "Visit: " << v << endl;EdgeNode* curr = graph.getEdges(v);while (curr) {if (!visited[curr->dest]) {visited[curr->dest] = true;q.push(curr->dest);}curr = curr->next;}}
}
四、经典图算法实现
4.1 Dijkstra 最短路径算法
vector<int> dijkstra(const AdjListGraph& graph, int src) {const int INF = INT_MAX;vector<int> dist(graph.size(), INF);priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;dist[src] = 0;pq.emplace(0, src);while (!pq.empty()) {auto [d, u] = pq.top();pq.pop();if (d > dist[u]) continue;EdgeNode* curr = graph.getEdges(u);while (curr) {int v = curr->dest;int w = curr->weight;if (dist[v] > dist[u] + w) {dist[v] = dist[u] + w;pq.emplace(dist[v], v);}curr = curr->next;}}return dist;
}
4.2 Prim 最小生成树算法
int primMST(const AdjListGraph& graph) {const int INF = INT_MAX;vector<int> key(graph.size(), INF);vector<bool> inMST(graph.size(), false);priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;key[0] = 0;pq.emplace(0, 0);int totalWeight = 0;while (!pq.empty()) {auto [k, u] = pq.top();pq.pop();if (inMST[u]) continue;inMST[u] = true;totalWeight += k;EdgeNode* curr = graph.getEdges(u);while (curr) {int v = curr->dest;int w = curr->weight;if (!inMST[v] && w < key[v]) {key[v] = w;pq.emplace(key[v], v);}curr = curr->next;}}return totalWeight;
}
五、图的应用场景
5.1 社交网络分析
-
顶点:用户
-
边:关注/好友关系
-
算法应用:推荐系统(BFS扩展好友)、影响力分析(PageRank)
5.2 路径规划系统
-
顶点:地点
-
边:道路(权重=距离/时间)
-
算法应用:最短路径(Dijkstra)、实时导航(A*算法)
5.3 任务调度系统
-
顶点:任务
-
边:依赖关系(有向边)
-
算法应用:拓扑排序检测循环依赖
六、性能优化技巧
6.1 数据结构选择策略
图类型 | 推荐存储结构 | 理由 |
---|---|---|
稠密图 | 邻接矩阵 | 快速访问任意边 |
稀疏图 | 邻接表 | 节省内存 |
动态变化图 | 邻接表 | 高效增删边操作 |
需要频繁判断邻接 | 邻接矩阵 | O(1)时间判断 |
6.2 内存管理优化
// 使用智能指针管理边节点
class SafeAdjListGraph {
private:struct EdgeNode {int dest;shared_ptr<EdgeNode> next;};vector<shared_ptr<EdgeNode>> vertices;
};
6.3 并行计算优化
// 使用OpenMP并行处理边
void parallelBFS(const AdjListGraph& graph, int start) {// ...#pragma omp parallel forfor (EdgeNode* curr = graph.getEdges(u); curr; curr = curr->next) {// 并行处理邻接节点}
}
七、现代C++图实现示例
template <typename VertexType, typename EdgeType = int>
class Graph {
private:unordered_map<VertexType, list<pair<VertexType, EdgeType>>> adjList;public:void addVertex(const VertexType& v) {adjList.emplace(v, list<pair<VertexType, EdgeType>>());}void addEdge(const VertexType& from, const VertexType& to, EdgeType weight = 1) {adjList[from].emplace_back(to, weight);}auto dijkstra(const VertexType& start) -> unordered_map<VertexType, EdgeType> {// 实现Dijkstra算法...}// 其他算法实现...
};// 使用示例
Graph<string> cityGraph;
cityGraph.addVertex("Beijing");
cityGraph.addVertex("Shanghai");
cityGraph.addEdge("Beijing", "Shanghai", 1200); // 公里数
八、总结与学习资源
8.1 关键要点
-
存储结构选择:根据场景选择矩阵或邻接表
-
算法复杂度认知:DFS/BFS O(V+E),Dijkstra O(E log V)
-
现代C++实践:使用STL容器和智能指针
-
性能优化方向:并行处理、内存布局优化
8.2 推荐学习路径
-
基础理论:《算法导论》图论章节
-
算法可视化:VisuAlgo.net 图算法演示
-
高性能实现:Boost Graph Library (BGL)
-
领域应用:社交网络分析、推荐系统论文
“图是描述复杂关系的终极工具——从微小的分子结构到浩瀚的宇宙网络,皆可用图建模。” —— 匿名算法工程师
通过掌握图的存储结构与经典算法,开发者可以解锁解决复杂系统问题的能力。建议结合具体应用场景进行实践,逐步深入理解这一强大的数据结构。