跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++算法

图论算法入门:深入理解 DFS、BFS 与树图遍历

综述由AI生成图论算法核心在于 DFS 与 BFS 的实现与应用。DFS 利用栈结构进行深度探索,适用于全排列、N 皇后等回溯问题,需注意状态恢复与剪枝优化。BFS 基于队列逐层扩展,天然具备求解最短路径的能力,常用于迷宫寻路。此外,文章还介绍了图的邻接表存储(链式前向星)及其在树与图遍历中的具体实践,通过 C++ 代码演示了如何高效处理节点距离计算与路径记录。

云朵棉花糖发布于 2026/2/12更新于 2026/5/43 浏览
图论算法入门:深入理解 DFS、BFS 与树图遍历

图论算法基础

图论是数据结构与算法中的核心章节,主要涉及图的存储、深度优先搜索(DFS)和广度优先搜索(BFS)。本文将结合 C++ 代码,解析这两种遍历方式的核心逻辑、适用场景及优化技巧。

深度优先搜索 (DFS)

DFS 像一位执着探索者,它倾向于沿着一条路径深入到底,直到叶子节点或无法继续为止,然后回溯尝试其他分支。从数据结构角度看,DFS 依赖栈(递归隐式使用系统栈),空间复杂度与搜索深度成正比,约为 O(h)。由于它是'一条路走到头',因此不具备直接求解最短路的性质。

经典案例:全排列问题

通过 DFS 生成 1 到 n 的全排列。我们需要记录当前路径 path 和已访问状态 st。当到达第 n 层时输出结果,回溯时需恢复现场(将 st[i] 重置为 false),而 path 数组无需手动清空,因为下一次循环会直接覆盖旧值。

#include <iostream>
using namespace std;

const int N = 10;
int n;
int path[N];
bool st[N];

void dfs(int u) {
    if (u == n) {
        for (int i = 0; i < n; i++) printf("%d ", path[i]);
        puts("");
        return;
    }
    for (int i = 1; i <= n; i++) {
        if (!st[i]) {
            path[u] = i;
            st[i] = true;
            dfs(u + 1);
            // 恢复现场
            st[i] = false;
        }
    }
}

int main() {
    cin >> n;
    dfs(0);
     ;
}
return
0

剪枝操作:N 皇后问题

在搜索过程中,如果当前状态已经无法满足约束条件,可以提前终止该分支的搜索,这就是剪枝。以 N 皇后为例,需要判断列、正对角线、反对角线是否冲突。

  • 列:直接用 col[i] 标记。
  • 正对角线:满足 y = x + b,即 b = x - y。为避免负数索引,统一加上偏移量 n,变为 x - y + n。
  • 反对角线:满足 y = -x + b,即 b = x + y。
#include <iostream>
using namespace std;

const int N = 10;
int n;
char g[N][N];
bool col[N], dg[N], udg[N]; // 列,正对角线,反对角线

void dfs(int u) {
    if (u == n) {
        for (int i = 0; i < n; i++) puts(g[i]);
        puts("");
        return;
    }
    for (int i = 0; i < n; i++) {
        if (!col[i] && !dg[u + i] && !udg[n - u + i]) {
            g[u][i] = 'Q';
            col[i] = dg[u + i] = udg[n + i - u] = true;
            dfs(u + 1);
            // 恢复现场
            g[u][i] = '.';
            col[i] = dg[u + i] = udg[n + i - u] = false;
        }
    }
}

int main() {
    cin >> n;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++) g[i][j] = '.';
    dfs(0);
    return 0;
}

广度优先搜索 (BFS)

BFS 则像一位眼观六路的观察者,它按层进行搜索,每次扩展离起点最近的未访问节点。从数据结构看,BFS 依赖队列。其空间复杂度通常为 O(2^h),但优势在于天然具备最短路性质,适合求无权图的最短距离。

宽搜通常有固定框架:初始化队列,入队起点,循环取出队首元素并扩展邻居。若需还原路径,可额外维护一个 Prev 数组记录每个点的前驱节点。

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 1e2 + 10;
typedef pair<int, int> PII;

int n, m;
int g[N][N];
int d[N][N]; // 记录距离
PII q[N * N], Prev[N][N]; // 队列和前驱记录

int bfs() {
    int hh = 0, tt = 0;
    q[0] = {0, 0};
    memset(d, -1, sizeof(d));
    d[0][0] = 0;

    int dx[4] = {-1, 0, 1, 0};
    int dy[4] = {0, 1, 0, -1};

    while (hh <= tt) {
        auto t = q[hh++];
        for (int i = 0; i < 4; i++) {
            int x = t.first + dx[i], y = t.second + dy[i];
            if (x >= 0 && x < n && y >= 0 && y < m && g[x][y] == 0 && d[x][y] == -1) {
                d[x][y] = d[t.first][t.second] + 1;
                Prev[x][y] = t; // 记录前驱
                q[++tt] = {x, y};
            }
        }
    }
    return d[n - 1][m - 1];
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) cin >> g[i][j];
    cout << bfs();
    return 0;
}

树与图的存储及遍历

树是一种特殊的无环图。在实际编程中,我们通常不区分树和图的存储方式,统一处理为图。

图的存储

图分为有向图和无向图。无向图边是双向的,有向图则是单向的。存储方式主要有邻接矩阵和邻接表:

  • 邻接矩阵:适合稠密图,但空间浪费大。
  • 邻接表:适合稀疏图,常用静态链表实现,即链式前向星。

链式前向星利用三个数组 head, next, to (或 e) 来模拟链表,效率较高且易于实现。

树与图的遍历

基于上述存储结构,我们可以复用 DFS 和 BFS 模板对图进行遍历。例如,计算图中每个点到起点的距离,或寻找最小割点等。

以下示例展示了如何使用 BFS 计算图中节点 1 到其他所有节点的距离,并返回节点 n 的距离。

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 1e5 + 10;
int n, m, q[N], d[N];
int e[N], h[N], idx, ne[N];

// 添加边 a -> b
void add(int a, int b) {
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
}

int bfs() {
    int hh = 0, tt = 0;
    q[0] = 1;
    memset(d, -1, sizeof(d));
    d[1] = 0;

    while (hh <= tt) {
        int t = q[hh++];
        for (int i = h[t]; i != -1; i = ne[i]) {
            int j = e[i];
            if (d[j] == -1) {
                d[j] = d[t] + 1;
                q[++tt] = j;
            }
        }
    }
    return d[n];
}

int main() {
    cin >> n >> m;
    memset(h, -1, sizeof(h));
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b;
        add(a, b);
    }
    cout << bfs();
    return 0;
}

掌握这些基础模板后,面对复杂的图论题目,只需根据具体需求调整状态定义和转移逻辑即可。

目录

  1. 图论算法基础
  2. 深度优先搜索 (DFS)
  3. 经典案例:全排列问题
  4. 剪枝操作:N 皇后问题
  5. 广度优先搜索 (BFS)
  6. 树与图的存储及遍历
  7. 图的存储
  8. 树与图的遍历
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Trae + Git 本地仓库离线管理指南
  • AI 数字人:繁荣背后的伦理困境与法律迷局
  • OpenAkita:自我进化的开源 AI 助手框架
  • 6 克 ESP32 微型无人机:手机 Wi-Fi 遥控系统设计与实现
  • 微服务韧性演进史:从 Hystrix 到 Service Mesh
  • Python 基于 Flask 的博物馆文物报修管理系统设计与实现
  • OpenClaw 框架 30+ 真实场景深度解析
  • OpenClaw 30+ 真实场景全拆解:从研发提效到企业级架构
  • Vivado 生成 MCS 文件并烧录 FLASH 实现 FPGA 掉电启动
  • 深度可分离卷积原理详解及 OPPORTUNITY 数据集实战
  • Python 和 R 语言,数据科学学哪个?
  • Open-AutoGLM 实现梦幻西游自动任务的技术解析与实测
  • Linux 下 C/C++ 调试工具 GDB 实战指南
  • 解决新机型 Copilot 键替代右 Ctrl 键问题
  • 从 0 到 1 打造 RISC-V 智能家居中控:硬件 + 固件 + 通信全链路实战
  • DeepSeek 深度使用指南与高效提示词技巧
  • Llama-3.2V-11B-COT 教育场景解题推理辅助应用实战
  • PowerShell Invoke-WebRequest 报错 Invalid URL 与 CommandNotFound 排查指南
  • ClawdBot 个人 AI 助理完整安装与配置教程
  • FreeCAD Python API 入门与实战指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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