现在位置: 首页 > C 语言数据结构与算法 > 正文

数据结构 - 图

图(Graph)是一种更为通用的非线性数据结构,用于表示元素之间"多对多"的复杂关系,由顶点和连接顶点的边构成。


图的基本概念

图的类型 — 无向图、有向图、带权图

无向图

0
1
边无方向,连接是对等的
例:社交网络好友关系

有向图

0
1
边有方向,单向连接
例:关注关系、网页链接

带权图

0
5
1
边附带权重(距离/代价)
例:地图导航、网络延迟

图的存储方式

邻接矩阵 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;
}

图的应用场景

场景典型算法
最短路径Dijkstra、Bellman-Ford(地图导航)
最小生成树Prim、Kruskal(网络布线优化)
拓扑排序Kahn 算法(任务依赖关系分析)
社交网络分析PageRank、社区发现