跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C算法

图结构邻接表实现:DFS、BFS 及 Dijkstra 算法详解

基于邻接表存储的图数据结构,实现了深度优先搜索(DFS)、广度优先搜索(BFS)及 Dijkstra 最短路径算法。内容涵盖图的构建、遍历逻辑、贪心选择策略证明及完整 C 语言代码示例,并对比了 DFS/BFS 在求解最短路径中的应用差异。

时间旅人发布于 2026/2/20更新于 2026/9/1061 浏览

图(邻接表)- DFS/BFS/Dijkstra 算法

基于一道简单实验,学习用邻接表结构储存图,并且包含 DFS/BFS 两种遍历方式,以及 Dijkstra 算法(朴素版)在本题的使用。

头文件(以及相关内容)
#include <cstdio>
#include <cstdlib>
#define MAX_VERTEX_NUM 20
#define INFINITY 0x3f3f3f3f
typedef char VertexType;
1. 邻接表的构建

包含三个部分:

  1. 边节点
    • 所指向边节点的索引(adjvex)
    • 指向下一边节点的指针(nextarc)
  2. 顶点节点
    • 储存该节点的信息(data)-----节点名称等
    • 指向边节点的指针(firstarc)
  3. 组合成邻接表
    • 顶点数组(vertices)
    • 顶点数(vexnum)
    • 边数(arcnum)
代码如下:
// 边节点结构
typedef struct ArcNode {
    // 该边指向的点节点的索引
    int adjvex;
    // 权值
    int value;
    // 指向下一个边节点的指针
    struct ArcNode* nextarc;
} ArcNode;

// 顶点节点的结构
typedef struct VNode {
    // 顶点节点的数据(顶点节点的名称)
    VertexType data;
    // 指向的第一个边节点
    ArcNode* firstarc;
} VNode, adjList[MAX_VERTEX_NUM];

// 邻接表表示的图的结构
typedef struct ALGraph {
    // 顶点数组
    adjList vertices;
    // 顶点数,边数
    int vexnum, arcnum;
} ALGraph;
2. 两种遍历

复用函数(vis — 表示该顶点是否被访问;Visit 函数 — 访问该节点后的行为:打印节点信息)

int vis[MAX_VERTEX_NUM];
void Visit(const ALGraph &G, int v) {
    printf("%c ", G.vertices[v].data);
}
DFS 遍历
void DFS(const ALGraph &G, int v) {
    vis[v] = 1;
    Visit(G, v);
    ArcNode* p = G.vertices[v].firstarc;
    while (p != NULL) {
        int w = p->adjvex;
        if (!vis[w]) {
            DFS(G, w);
        }
        p = p->nextarc;
    }
}

void DFSTraverse(const ALGraph &G) {
    int n = G.vexnum;
    for (int i = 0; i < n; i++) {
        vis[i] = 0;
    }
    for (int i = 0; i < n; i++) {
        if (!vis[i]) {
            DFS(G, i);
        }
    }
}
BFS 遍历

(为简化演示,不使用 STL 队列,采用双指针的移动来模拟入队、出队操作) 注:front++相当于出队,rear++相当于入队

void BFS(const ALGraph &G, int v) {
    int Queue[MAX_VERTEX_NUM];
    int front = 0, rear = 0;
    vis[v] = 1;
    Visit(G, v);
    Queue[rear++] = v;
    while (front < rear) {
        int u = Queue[front];
        front++;
        ArcNode* p = G.vertices[u].firstarc;
        while (p != NULL) {
            int w = p->adjvex;
            if (!vis[w]) {
                vis[w] = 1;
                Visit(G, w);
                Queue[rear++] = w;
            }
            p = p->nextarc;
        }
    }
}

void BFSTraverse(const ALGraph &G) {
    int n = G.vexnum;
    for (int i = 0; i < n; i++) {
        vis[i] = 0;
    }
    for (int i = 0; i < n; i++) {
        if (!vis[i]) {
            BFS(G, i);
        }
    }
}
3. Dijkstra 算法 (朴素版)

主要核心:

  1. 初始化距离:设定源节点到自身的距离为 0,到其他所有节点的距离为 (INFINITY:0x3f3f3f3f)。
  2. 贪心选择:每次从未确定最短路径的节点中,选择当前距离源节点最近的节点 u,将其标记为'已确定最短路径'。(dist[u])
  3. 松弛操作:对节点 u 的所有邻接节点 v,尝试通过 u 更新 v 的最短距离。松弛条件:若 dist[v] > dist[u] + w(u, v),则更新 dist[v] = dist[u] + w(u, v)。
  4. 重复步骤 2-3:直到所有节点都被标记为'已确定最短路径'。
Dijkstra 算法贪心选择正确性证明:
  1. 前提
    • 图中所有边权非负;
    • S:已确定最短路径的节点集合;
    • dist[u]:当前已知 s 到 u 的最短距离上界。
  2. 反证法证明 假设:选 u 时,存在更短的 s→u 路径 P,长度<dist[u]。拆分路径 P:s→…→x(x∈S,P 上最后一个在 S 中的节点)→y(y∉S,P 上第一个不在 S 中的节点)→…→u。 因 x∈S,其最短路径已确定(dist[x] = 真实最短距离);又边权非负,所以 s→y 的真实最短距离 ≤ s→x→y 的长度 ≤ 路径 P 的长度(y 到 u 的路径权值≥0,不会缩短)。 结合假设'P 长度<dist[u]',可推出:s→y 的真实最短距离 < dist[u]。但 dist[y] 是 s→y 的距离上界(dist[y]≥真实最短距离),因此 dist[y] < dist[u]。 这与「u 是当前未确定节点中 dist 最小的节点」矛盾,故假设不成立。
  3. 结论 每次选的 u,其当前 dist[u] 就是 s 到 u 的最短路径,后续不会被更新。

(代码如下:)

// 通过 Dijkstra 算法求最短路径
int Dijkstra(const ALGraph &G, int start) {
    int n = G.vexnum;
    int* dist = (int*)malloc(n * sizeof(int)); // dist[i] 与起点的距离
    int* visited = (int*)malloc(n * sizeof(int)); // visited[i]==1 时,最短路径确定
    
    // 初始化
    for (int i = 0; i < n; i++) {
        dist[i] = INFINITY;
        visited[i] = 0;
    }
    dist[start] = 0;
    
    for (int i = 0; i < n; i++) {
        int u = -1;
        int min_dist = INFINITY;
        
        // (贪心选择)
        // 从未确定的顶点中,找距离起点最近的顶点,找到后该顶点距离起点的最短距离即可确定
        for (int j = 0; j < n; j++) {
            if (!visited[j] && dist[j] < min_dist) {
                min_dist = dist[j];
                u = j;
            }
        }
        
        if (u == -1) break;
        visited[u] = 1;
        if (u == n - 1) break;
        
        // 松弛操作
        ArcNode* p = G.vertices[u].firstarc;
        while (p != NULL) {
            int v = p->adjvex;
            int w = p->value;
            if (!visited[v] && dist[u] != INFINITY && dist[u] + w < dist[v]) {
                dist[v] = dist[u] + w;
            }
            p = p->nextarc;
        }
    }
    
    int result = dist[n - 1];
    free(dist);
    free(visited);
    return result;
}
4. 综上所述(完整代码如下)
#include <cstdio>
#include <cstdlib>
#define MAX_VERTEX_NUM 20
#define INFINITY 0x3f3f3f3f
typedef char VertexType;

// 边节点结构
typedef struct ArcNode {
    // 该边指向的点节点的索引
    int adjvex;
    // 权值
    int value;
    // 指向下一个边节点的指针
    struct ArcNode* nextarc;
} ArcNode;

// 顶点节点的结构
typedef struct VNode {
    // 顶点节点的数据(顶点节点的名称)
    VertexType data;
    // 指向的第一个边节点
    ArcNode* firstarc;
} VNode, adjList[MAX_VERTEX_NUM];

// 邻接表表示的图的结构
typedef struct ALGraph {
    // 顶点数组
    adjList vertices;
    // 顶点数,边数
    int vexnum, arcnum;
} ALGraph;

// 返回节点在数组中的索引
int LocateVex(const ALGraph &G, VertexType V) {
    for (int i = 0; i < G.vexnum; i++) {
        if (G.vertices[i].data == V) return i;
    }
    return -1;
}

// 图的创建
int CreateDG(ALGraph &G) {
    // 输入顶点数和边数
    printf("请输入顶点数与边数:\n");
    scanf("%d %d", &G.vexnum, &G.arcnum);
    getchar();
    
    // 输入顶点信息(顶点的名称等)
    printf("请输入%d个顶点的信息:\n", G.vexnum);
    for (int i = 0; i < G.vexnum; i++) {
        scanf("%c", &G.vertices[i].data);
        getchar();
        // 初始化
        G.vertices[i].firstarc = NULL;
    }
    
    // 输入边的信息
    VertexType V1, V2;
    int v;
    ArcNode* p;
    printf("请输入%d条边的信息:\n", G.arcnum);
    for (int k = 0; k < G.arcnum; k++) {
        scanf("%c %c %d", &V1, &V2, &v);
        getchar();
        int i = LocateVex(G, V1);
        int j = LocateVex(G, V2);
        if (i == -1 || j == -1) return 0;
        p = (ArcNode*)malloc(sizeof(ArcNode));
        p->adjvex = j;
        p->value = v;
        // 头插法
        p->nextarc = G.vertices[i].firstarc;
        G.vertices[i].firstarc = p;
    }
    return 1;
}

// 遍历
int vis[MAX_VERTEX_NUM];
void Visit(const ALGraph &G, int v) {
    printf("%c ", G.vertices[v].data);
}

// DFS
void DFS(const ALGraph &G, int v) {
    vis[v] = 1;
    Visit(G, v);
    ArcNode* p = G.vertices[v].firstarc;
    while (p != NULL) {
        int w = p->adjvex;
        if (!vis[w]) {
            DFS(G, w);
        }
        p = p->nextarc;
    }
}

void DFSTraverse(const ALGraph &G) {
    int n = G.vexnum;
    for (int i = 0; i < n; i++) {
        vis[i] = 0;
    }
    for (int i = 0; i < n; i++) {
        if (!vis[i]) {
            DFS(G, i);
        }
    }
}

// BFS
void BFS(const ALGraph &G, int v) {
    int Queue[MAX_VERTEX_NUM];
    int front = 0, rear = 0;
    vis[v] = 1;
    Visit(G, v);
    Queue[rear++] = v;
    while (front < rear) {
        int u = Queue[front];
        front++;
        ArcNode* p = G.vertices[u].firstarc;
        while (p != NULL) {
            int w = p->adjvex;
            if (!vis[w]) {
                vis[w] = 1;
                Visit(G, w);
                Queue[rear++] = w;
            }
            p = p->nextarc;
        }
    }
}

void BFSTraverse(const ALGraph &G) {
    int n = G.vexnum;
    for (int i = 0; i < n; i++) {
        vis[i] = 0;
    }
    for (int i = 0; i < n; i++) {
        if (!vis[i]) {
            BFS(G, i);
        }
    }
}

// 通过 Dijkstra 算法求最短路径
int Dijkstra(const ALGraph &G, int start) {
    int n = G.vexnum;
    int* dist = (int*)malloc(n * sizeof(int));
    int* visited = (int*)malloc(n * sizeof(int));
    
    // 初始化
    for (int i = 0; i < n; i++) {
        dist[i] = INFINITY;
        visited[i] = 0;
    }
    dist[start] = 0;
    
    for (int i = 0; i < n; i++) {
        int u = -1;
        int min_dist = INFINITY;
        
        // (贪心选择)
        for (int j = 0; j < n; j++) {
            if (!visited[j] && dist[j] < min_dist) {
                min_dist = dist[j];
                u = j;
            }
        }
        
        if (u == -1) break;
        visited[u] = 1;
        if (u == n - 1) break;
        
        // 松弛操作
        ArcNode* p = G.vertices[u].firstarc;
        while (p != NULL) {
            int v = p->adjvex;
            int w = p->value;
            if (!visited[v] && dist[u] != INFINITY && dist[u] + w < dist[v]) {
                dist[v] = dist[u] + w;
            }
            p = p->nextarc;
        }
    }
    
    int result = dist[n - 1];
    free(dist);
    free(visited);
    return result;
}

// 主程序
int main() {
    ALGraph G;
    if (CreateDG(G)) {
        printf("成功\n");
    } else printf("失败\n");
    
    // DFS 遍历
    printf("DFS 遍历结果:");
    DFSTraverse(G);
    printf("\n");
    
    // BFS 遍历
    printf("BFS 遍历结果:");
    BFSTraverse(G);
    printf("\n");
    
    int min = Dijkstra(G, 0);
    printf("%d", min);
    return 0;
}
5. 补充(用 DFS/BFS 解决该题)
DFS
#include <cstdio>
#include <cstdlib>
#define MAX_VERTEX_NUM 20
#define INFINITY 0x3f3f3f3f
typedef char VertexType;

// 边节点
typedef struct ArcNode {
    int adjvex;
    int value;
    struct ArcNode* nextarc;
} ArcNode;

// 顶点节点
typedef struct VNode {
    VertexType data;
    ArcNode* firstarc;
} VNode, adjList[MAX_VERTEX_NUM];

// 构建邻接表
typedef struct ALgraph {
    adjList vertices;
    int vexnum, arcnum;
} ALgraph;

// 返回节点的索引
int LocateVex(const ALgraph &G, VertexType e) {
    for (int i = 0; i < G.vexnum; i++) {
        if (G.vertices[i].data == e) {
            return i;
        }
    }
    return -1;
}

// 创建图
int CreateDG(ALgraph &G) {
    printf("请输入顶点数和边数:\n");
    scanf("%d %d", &G.vexnum, &G.arcnum);
    getchar();
    printf("请输入顶点的信息:\n");
    for (int i = 0; i < G.vexnum; i++) {
        scanf("%c", &G.vertices[i].data);
        getchar();
        G.vertices[i].firstarc = NULL;
    }
    printf("请输入边的关系:\n");
    ArcNode* p;
    VertexType V1, V2;
    int v;
    for (int k = 0; k < G.arcnum; k++) {
        scanf("%c %c %d", &V1, &V2, &v);
        getchar();
        int i = LocateVex(G, V1);
        int j = LocateVex(G, V2);
        if (i == -1 || j == -1) {
            return 0;
        }
        p = (ArcNode*)malloc(sizeof(ArcNode));
        p->adjvex = j;
        p->value = v;
        p->nextarc = G.vertices[i].firstarc;
        G.vertices[i].firstarc = p;
    }
    return 1;
}

// 用 DFS 求第一个顶点到最后一个顶点的最短路径
int min_dist = INFINITY;
int cur_dist = 0;
int visited[MAX_VERTEX_NUM];

void DFS(const ALgraph &G, int idx) {
    int n = G.vexnum;
    if (idx == n - 1) {
        if (cur_dist < min_dist) min_dist = cur_dist;
        return;
    }
    visited[idx] = 1;
    ArcNode* p = G.vertices[idx].firstarc;
    while (p != NULL) {
        int next_idx = p->adjvex;
        int weight = p->value;
        if (!visited[next_idx]) {
            cur_dist += weight;
            DFS(G, next_idx);
            cur_dist -= weight;
        }
        p = p->nextarc;
    }
    visited[idx] = 0;
}

int main() {
    ALgraph G;
    if (CreateDG(G)) {
        printf("创建成功\n");
    } else printf("创建失败\n");
    
    for (int i = 0; i < G.vexnum; i++) {
        visited[i] = 0;
    }
    DFS(G, 0);
    printf("%d", min_dist);
    return 0;
}
BFS
#include <cstdio>
#include <cstdlib>
#define MAX_VERTEX_NUM 20
#define INFINITY 0x3f3f3f3f
typedef char VertexType;

// 边节点
typedef struct ArcNode {
    int adjvex;
    int value;
    struct ArcNode* nextarc;
} ArcNode;

// 顶点节点
typedef struct VNode {
    VertexType data;
    ArcNode* firstarc;
} VNode, adjList[MAX_VERTEX_NUM];

// 构建邻接表
typedef struct ALgraph {
    adjList vertices;
    int vexnum, arcnum;
} ALgraph;

// 返回节点的索引
int LocateVex(const ALgraph &G, VertexType e) {
    for (int i = 0; i < G.vexnum; i++) {
        if (G.vertices[i].data == e) {
            return i;
        }
    }
    return -1;
}

// 创建图
int CreateDG(ALgraph &G) {
    printf("请输入顶点数和边数:\n");
    scanf("%d %d", &G.vexnum, &G.arcnum);
    getchar();
    printf("请输入顶点的信息:\n");
    for (int i = 0; i < G.vexnum; i++) {
        scanf("%c", &G.vertices[i].data);
        getchar();
        G.vertices[i].firstarc = NULL;
    }
    printf("请输入边的关系:\n");
    ArcNode* p;
    VertexType V1, V2;
    int v;
    for (int k = 0; k < G.arcnum; k++) {
        scanf("%c %c %d", &V1, &V2, &v);
        getchar();
        int i = LocateVex(G, V1);
        int j = LocateVex(G, V2);
        if (i == -1 || j == -1) {
            return 0;
        }
        p = (ArcNode*)malloc(sizeof(ArcNode));
        p->adjvex = j;
        p->value = v;
        p->nextarc = G.vertices[i].firstarc;
        G.vertices[i].firstarc = p;
    }
    return 1;
}

// 用 BFS 求第一个顶点到最后一个顶点的最短路径
typedef struct QNode {
    int idx;
    int path_len; // 起点到路径的长度
} QNode;

int BFS(const ALgraph &G) {
    int n = G.vexnum;
    int* dist = (int*)malloc(n * sizeof(int));
    for (int i = 0; i < n; i++) {
        dist[i] = INFINITY;
    }
    QNode queue[MAX_VERTEX_NUM * 10];
    int front = 0, rear = 0;
    queue[rear].idx = 0;
    queue[rear].path_len = 0;
    rear++;
    
    while (front < rear) {
        QNode cur = queue[front];
        front++;
        int cur_idx = cur.idx;
        int cur_len = cur.path_len;
        
        if (cur_len > dist[cur_idx]) continue;
        
        ArcNode* p = G.vertices[cur_idx].firstarc;
        while (p != NULL) {
            int next_idx = p->adjvex;
            int weight = p->value;
            int new_len = cur_len + weight;
            
            if (new_len < dist[next_idx]) {
                dist[next_idx] = new_len;
                queue[rear].idx = next_idx;
                queue[rear].path_len = new_len;
                rear++;
            }
            p = p->nextarc;
        }
    }
    
    int result = dist[n - 1];
    free(dist);
    return result;
}

int main() {
    ALgraph G;
    if (CreateDG(G)) {
        printf("创建成功\n");
    } else printf("创建失败\n");
    
    int result = BFS(G);
    printf("%d", result);
    return 0;
}

目录

  1. 图(邻接表)- DFS/BFS/Dijkstra 算法
  2. 头文件(以及相关内容)
  3. 1. 邻接表的构建
  4. 代码如下:
  5. 2. 两种遍历
  6. DFS 遍历
  7. BFS 遍历
  8. 3. Dijkstra 算法 (朴素版)
  9. Dijkstra 算法贪心选择正确性证明:
  10. 4. 综上所述(完整代码如下)
  11. 5. 补充(用 DFS/BFS 解决该题)
  12. DFS
  13. BFS

更多推荐文章

查看全部
  • 上手 Z-Image-Turbo:一个快到不像 AI 的文生图工具
  • 腾讯云轻量应用服务器部署 OpenClaw 并接入 QQ 飞书机器人
  • DankDroneDownloader:大疆无人机固件下载工具使用指南
  • 前端登录页“记住密码”功能的实现原理与最佳实践
  • 宇树机器人 G1 导航仿真:地图转换与参数配置
  • OpenClaw 安装百度网页搜索技能
  • 2026年AI辅助毕业论文写作工具盘点与使用指南
  • 2025 机构技术栈:14 款 Web 模板与插件评审
  • RVC 语音变声器快速上手:AI 翻唱与实时变声教程
  • Android 离线语音识别指南:基于 Whisper 实现本地语音转文字
  • Python 爬虫架构:基于 Selenium 与 ScrapyRT 的高并发动态网页抓取
  • 5 款主流开源 AI Agent 框架深度解析
  • 千笔 AI 辅助写作工具核心功能解析
  • Double DQN 算法原理与 Python 实现
  • MCP 服务器大全:分类汇总与开发指南
  • 鸿蒙金融理财全栈项目:风险控制、合规审计与产品创新
  • 2024 年程序员入门大模型必读书单推荐
  • 基于 LangGraph 实现模块化 Skills 型 AI Agent
  • 2024 大模型面试 100 道精选真题及答案解析
  • Ubuntu 双系统下 NVIDIA 显卡驱动安装指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online