一、图的本质与核心结构
图是描述多对多关系的数据结构,由顶点集合V和边集合E组成。每个顶点代表一个实体,边描述实体间的关系。
1.1 图的表示方法
邻接矩阵(稠密图)
class GraphMatrix {
private:
vector<vector<int>> matrix; // 二维数组存储边信息
int vertexCount;
public:
GraphMatrix(int n) : vertexCount(n), matrix(n, vector<int>(n, 0)) {}
void addEdge(int u, int v, int weight = 1) {
matrix[u][v] = weight;
matrix[v][u] = weight; // 无向图需双向设置
}
};
邻接表(稀疏图)
struct EdgeNode {
int adjvex;
int weight;
EdgeNode* next;
EdgeNode(int v, int w) : adjvex(v), weight(w), next(nullptr) {}
};
class GraphList {
private:
vector<EdgeNode*> adjList;
int vertexCount;
public:
GraphList(int n) : vertexCount(n), adjList(n, nullptr) {}
void addEdge(int u, int v, int weight = 1) {
EdgeNode* newNode = new EdgeNode(v, weight);
newNode->next = adjList[u];
adjList[u] = newNode;
}
};
二、图的六大核心算法
2.1 广度优先搜索(BFS)
void BFS(GraphList& graph, int start) {
vector<bool> visited(graph.vertexCount, false);
queue<int> q;
q.push(start);
visited[start] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
cout << u << " ";
EdgeNode* curr = graph.adjList[u];
while (curr) {
if (!visited[curr->adjvex]) {
visited[curr->adjvex] = true;
q.push(curr->adjvex);
}
curr = curr->next;
}
}
}
2.2 深度优先搜索(DFS)
void DFS(GraphList& graph, int u, vector<bool>& visited) {
visited[u] = true;
cout << u << " ";
EdgeNode* curr = graph.adjList[u];
while (curr) {
if (!visited[curr->adjvex])
DFS(graph, curr->adjvex, visited);
curr = curr->next;
}
}
2.3 Dijkstra最短路径
void dijkstra(GraphList& graph, int src) {
vector<int> dist(graph.vertexCount, INT_MAX);
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
dist[src] = 0;
pq.push({0, src});
while (!pq.empty()) {
auto [d, u] = pq.top();
pq.pop();
EdgeNode* curr = graph.adjList[u];
while (curr) {
if (dist[curr->adjvex] > d + curr->weight) {
dist[curr->adjvex] = d + curr->weight;
pq.push({dist[curr->adjvex], curr->adjvex});
}
curr = curr->next;
}
}
}
2.4 Floyd-Warshall全源最短路径
void floydWarshall(GraphMatrix& graph) {
int n = graph.vertexCount;
vector<vector<int>> dist = graph.matrix;
for (int k = 0; k < n; ++k)
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
if (dist[i][k] != INT_MAX && dist[k][j] != INT_MAX)
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
2.5 拓扑排序(Kahn算法)
vector<int> topologicalSort(GraphList& graph) {
vector<int> inDegree(graph.vertexCount, 0);
queue<int> q;
vector<int> result;
// 计算入度
for (int i = 0; i < graph.vertexCount; ++i) {
EdgeNode* curr = graph.adjList[i];
while (curr) {
inDegree[curr->adjvex]++;
curr = curr->next;
}
}
// 入队零入度节点
for (int i = 0; i < graph.vertexCount; ++i)
if (inDegree[i] == 0) q.push(i);
while (!q.empty()) {
int u = q.front();
q.pop();
result.push_back(u);
EdgeNode* curr = graph.adjList[u];
while (curr) {
if (--inDegree[curr->adjvex] == 0)
q.push(curr->adjvex);
curr = curr->next;
}
}
return result;
}
2.6 最小生成树(Prim算法)
void primMST(GraphList& graph) {
vector<int> key(graph.vertexCount, INT_MAX);
vector<bool> inMST(graph.vertexCount, false);
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
key[0] = 0;
pq.push({0, 0});
while (!pq.empty()) {
int u = pq.top().second;
pq.pop();
inMST[u] = true;
EdgeNode* curr = graph.adjList[u];
while (curr) {
if (!inMST[curr->adjvex] && curr->weight < key[curr->adjvex]) {
key[curr->adjvex] = curr->weight;
pq.push({key[curr->adjvex], curr->adjvex});
}
curr = curr->next;
}
}
}
三、高阶算法扩展
3.1 强连通分量(Kosaraju算法)
void kosarajuSCC(GraphList& graph) {
vector<bool> visited(graph.vertexCount, false);
stack<int> stk;
// 第一次DFS获取完成顺序
function<void(int)> fillOrder = [&](int u) {
visited[u] = true;
EdgeNode* curr = graph.adjList[u];
while (curr) {
if (!visited[curr->adjvex])
fillOrder(curr->adjvex);
curr = curr->next;
}
stk.push(u);
};
// 反转图
GraphList transposed(graph.vertexCount);
for (int u = 0; u < graph.vertexCount; ++u) {
EdgeNode* curr = graph.adjList[u];
while (curr) {
transposed.addEdge(curr->adjvex, u, curr->weight);
curr = curr->next;
}
}
// 第二次DFS按完成顺序处理
fill(visited.begin(), visited.end(), false);
while (!stk.empty()) {
int u = stk.top();
stk.pop();
if (!visited[u]) {
DFS(transposed, u, visited);
cout << endl;
}
}
}
四、复杂度分析
算法 | 时间复杂度 | 空间复杂度 |
---|---|---|
BFS/DFS | O(V+E) | O(V) |
Dijkstra | O((V+E)logV) | O(V) |
Floyd-Warshall | O(V3) | O(V2) |
Prim | O((V+E)logV) | O(V) |
Kosaraju | O(V+E) | O(V) |
五、应用场景
- 社交网络:使用BFS查找二度人脉
- 路径规划:Dijkstra实现最短路径导航
- 任务调度:拓扑排序检测依赖关系
- 电路设计:最小生成树优化布线成本
暮乘白帝过重山,期待与你的每一次相见。