数据结构 - 图
图(Graph)是一种更为通用的非线性数据结构,用于表示元素之间"多对多"的复杂关系,由顶点和连接顶点的边构成。
图的基本概念
图的类型 — 无向图、有向图、带权图
无向图
0
—1
边无方向,连接是对等的
例:社交网络好友关系
例:社交网络好友关系
有向图
0
→1
边有方向,单向连接
例:关注关系、网页链接
例:关注关系、网页链接
带权图
0
51
边附带权重(距离/代价)
例:地图导航、网络延迟
例:地图导航、网络延迟
图的存储方式
邻接矩阵 vs 邻接表
邻接矩阵
空间复杂度O(V²)
判断两点相连O(1)
遍历邻接点O(V)
适合:稠密图 · int graph[V][V]
邻接表
空间复杂度O(V+E)
判断两点相连O(度数)
遍历邻接点O(度数)
适合:稀疏图 · 链表数组
图的遍历
DFS vs BFS — 从顶点 0 开始遍历
DFS 深度优先
0→
1→
3→
4→
2→
5
沿一条路径走到头再回溯
实现:递归 / 栈 | 适合路径搜索、拓扑排序
BFS 广度优先
0→
1→
2→
3→
4→
5
按层扩展,同层先访问
实现:队列 | 天然适合无权图最短路径
实例
#include <stdio.h>
#include <stdbool.h>
#define V 6 /* 顶点数 */
/* 邻接矩阵表示的图 */
int graph[V][V] = {
{0,1,1,0,0,0}, /* 顶点 0 的邻接关系 */
{1,0,0,1,1,0}, /* 顶点 1 */
{1,0,0,0,1,0}, /* 顶点 2 */
{0,1,0,0,0,1}, /* 顶点 3 */
{0,1,1,0,0,1}, /* 顶点 4 */
{0,0,0,1,1,0} /* 顶点 5 */
};
bool visited[V];
/* DFS: 深度优先搜索,递归实现
特点:沿一条路径走到头再回溯,适合路径搜索和连通性判断 */
void DFS(int v) {
visited[v] = true;
printf("%d ", v); /* 访问当前顶点 */
for (int i = 0; i < V; i++) {
if (graph[v][i] && !visited[i]) {
DFS(i); /* 递归访问未访问的邻接顶点 */
}
}
}
/* BFS: 广度优先搜索,借助队列实现
特点:按层扩展,天然适合求解最短路径 */
void BFS(int start) {
bool visited[V] = {false};
int queue[V];
int front = 0, rear = 0;
visited[start] = true;
queue[rear++] = start; /* 起始顶点入队 */
while (front < rear) {
int v = queue[front++]; /* 出队 */
printf("%d ", v);
for (int i = 0; i < V; i++) {
if (graph[v][i] && !visited[i]) {
visited[i] = true;
queue[rear++] = i; /* 邻接顶点入队 */
}
}
}
}
int main() {
/* 初始化访问标记 */
for (int i = 0; i < V; i++) visited[i] = false;
printf("DFS (从顶点 0 开始): ");
DFS(0); /* 输出: 0 1 3 5 4 2 */
printf("\n");
printf("BFS (从顶点 0 开始): ");
BFS(0); /* 输出: 0 1 2 3 4 5 */
printf("\n");
return 0;
}
#include <stdbool.h>
#define V 6 /* 顶点数 */
/* 邻接矩阵表示的图 */
int graph[V][V] = {
{0,1,1,0,0,0}, /* 顶点 0 的邻接关系 */
{1,0,0,1,1,0}, /* 顶点 1 */
{1,0,0,0,1,0}, /* 顶点 2 */
{0,1,0,0,0,1}, /* 顶点 3 */
{0,1,1,0,0,1}, /* 顶点 4 */
{0,0,0,1,1,0} /* 顶点 5 */
};
bool visited[V];
/* DFS: 深度优先搜索,递归实现
特点:沿一条路径走到头再回溯,适合路径搜索和连通性判断 */
void DFS(int v) {
visited[v] = true;
printf("%d ", v); /* 访问当前顶点 */
for (int i = 0; i < V; i++) {
if (graph[v][i] && !visited[i]) {
DFS(i); /* 递归访问未访问的邻接顶点 */
}
}
}
/* BFS: 广度优先搜索,借助队列实现
特点:按层扩展,天然适合求解最短路径 */
void BFS(int start) {
bool visited[V] = {false};
int queue[V];
int front = 0, rear = 0;
visited[start] = true;
queue[rear++] = start; /* 起始顶点入队 */
while (front < rear) {
int v = queue[front++]; /* 出队 */
printf("%d ", v);
for (int i = 0; i < V; i++) {
if (graph[v][i] && !visited[i]) {
visited[i] = true;
queue[rear++] = i; /* 邻接顶点入队 */
}
}
}
}
int main() {
/* 初始化访问标记 */
for (int i = 0; i < V; i++) visited[i] = false;
printf("DFS (从顶点 0 开始): ");
DFS(0); /* 输出: 0 1 3 5 4 2 */
printf("\n");
printf("BFS (从顶点 0 开始): ");
BFS(0); /* 输出: 0 1 2 3 4 5 */
printf("\n");
return 0;
}
图的应用场景
| 场景 | 典型算法 |
|---|---|
| 最短路径 | Dijkstra、Bellman-Ford(地图导航) |
| 最小生成树 | Prim、Kruskal(网络布线优化) |
| 拓扑排序 | Kahn 算法(任务依赖关系分析) |
| 社交网络分析 | PageRank、社区发现 |
