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

图论寻路算法:深度优先搜索 (DFS) 实现

深度优先搜索是图遍历的基础算法之一。通过维护前驱节点数组记录路径,DFS 能够从起点出发探索所有可达顶点。展示了如何在 Java 中实现基于 DFS 的寻路类,包括初始化、递归遍历及路径回溯逻辑。相比广度优先搜索,DFS 不保证最短路径,但实现简单且内存占用较低,适用于迷宫求解、依赖解析等场景。

王者发布于 2025/11/9更新于 2026/10/2491 浏览
图论寻路算法:深度优先搜索 (DFS) 实现

图论寻路算法:深度优先搜索 (DFS) 实现

图的寻路算法是图论中的基础内容,核心目标是在两个顶点之间找到一条连通路径。深度优先搜索(DFS)作为一种经典的遍历策略,能够沿着图的深度方向尽可能远地探索路径。虽然它不能保证找到最短路径,但在许多场景下,其实现简单且效率可观。

一、算法核心思想

要实现基于 DFS 的寻路,关键在于记录访问状态和路径前驱。具体逻辑如下:

  1. 记录路径:使用 from 数组保存每个顶点的前驱节点,以便后续回溯。
  2. 深度优先遍历:从起点开始,递归访问所有未访问的邻接顶点。
  3. 路径回溯:一旦到达终点或完成遍历,通过 from 数组逆向还原完整路径。

数据结构设计

我们需要维护以下几个关键变量:

  • visited 数组:标记顶点是否已被访问,防止死循环。
  • from 数组:记录路径中每个顶点的前驱顶点索引。
  • s:起始顶点的索引。

二、代码实现详解

下面以 Java 为例,展示如何构建一个通用的寻路类 Path。这里假设已经有一个基础的 Graph 接口。

1. 核心数据结构定义

import java.util.Stack;
import java.util.Vector;

public class Path {
    private Graph G;        // 图的引用
    private int s;          // 起始点
    private boolean[] visited; // 记录访问过的节点
    private int[] from;     // 记录路径,from[i]表示 i 的前驱节点

    // 构造函数,寻路算法初始化
    public Path(Graph graph, int s) {
        G = graph;
        assert s >= 0 && s < G.V();
        
        visited = new boolean[G.V()];
        from = new int[G.V()];
        
        for (int i = 0; i < G.V(); i++) {
            visited[i] = false;
            from[i] = -1;
        }
        this.s = s;
        dfs(s); // 立即开始 DFS 遍历
    }

在构造函数中,我们不仅初始化了数组,还直接调用了 dfs(s)。这意味着寻路对象创建时,就已经完成了从起点出发的全图可达性分析。

2. DFS 遍历逻辑

这是算法的核心部分。每当我们访问一个新节点,就将其标记为已访问,并记录它是由哪个节点过来的。

    // 深度优先遍历
    private void dfs(int v) {
        visited[v] = true;
        for (int i : G.adj(v)) {
            if (!visited[i]) {
                from[i] = v; // 记录前驱顶点
                dfs(i);      // 递归访问邻居
            }
        }
    }

注意这里的 from[i] = v。这行代码至关重要,它建立了反向链接。当我们需要查询路径时,只需要从终点不断向前跳,直到回到起点即可。

3. 路径查询与展示

有了 visited 和 from,判断两点是否连通以及获取具体路径就变得很简单。

    // 判断是否有路径
    boolean hasPath(int w) {
        assert w >= 0 && w < G.V();
        return visited[w];
    }

    // 获取路径
    Vector<Integer> path(int w) {
        assert hasPath(w);
        Stack<Integer> stack = new Stack<>();
        int p = w;
        while (p != -1) {
            stack.push(p);
            p = from[p];
        }
        Vector<Integer> res = new Vector<>();
        while (!stack.empty()) res.add(stack.pop());
        return res;
    }

    // 打印路径
    void showPath(int w) {
        assert hasPath(w);
        Vector<Integer> vec = path(w);
        for (int i = 0; i < vec.size(); i++) {
            System.out.print(vec.elementAt(i));
            if (i != vec.size() - 1)
                System.out.print(" -> ");
        }
        System.out.println();
    }
}

在 path 方法中,我们利用栈结构将逆序的前驱链转换为正序的路径输出。这种写法避免了复杂的列表反转操作。

三、测试与应用

为了验证算法的正确性,我们可以构造一个简单的无向图进行测试。

public class PathTest {
    public static void main(String[] args) {
        // 创建一个包含 7 个顶点的稀疏图
        Graph g = new SparseGraph(7, false);
        g.addEdge(0, 1);
        g.addEdge(0, 2);
        g.addEdge(1, 3);
        g.addEdge(1, 4);
        g.addEdge(2, 5);
        g.addEdge(4, 6);

        // 寻路算法测试
        Path path = new Path(g, 0);
        
        System.out.println("Path from 0 to 6:");
        path.showPath(6); // 输出示例:0 -> 1 -> 4 -> 6
        
        System.out.println("Path from 0 to 5:");
        path.showPath(5); // 输出示例:0 -> 2 -> 5
        
        System.out.println("Has path to 3: " + path.hasPath(3));
        System.out.println("Has path to 6: " + path.hasPath(6));
    }
}

运行结果会显示具体的路径走向。例如从 0 到 6,DFS 可能会选择 0 -> 1 -> 4 -> 6,而不会选择更长的路径(如果存在的话)。

四、算法分析与优化

时间复杂度

操作时间复杂度
初始化O(V)
DFS 遍历O(V + E)
路径查询O(L),L 为路径长度

其中 V 代表顶点数,E 代表边数。由于每个顶点和每条边最多被访问一次,整体效率较高。

空间复杂度

主要消耗在于 visited 和 from 数组,均为 O(V)。对于大规模图,这通常是可接受的开销。

优化方向

  1. 广度优先搜索 (BFS):如果需要最短路径,应改用 BFS。
  2. 双向搜索:同时从起点和终点开始搜索,减少搜索空间。
  3. 启发式搜索:如 A*算法,适用于有权图或需要特定导向的场景。

五、DFS 与 BFS 对比

在实际开发中,选择哪种算法取决于需求:

  • DFS:使用栈或递归,不保证最短路径,但内存占用相对较小,适合寻找任意路径。
  • BFS:使用队列,保证找到最短路径(无权图),但内存消耗随层级增加。

建议:迷宫求解、依赖关系解析等对路径长度不敏感的场景,DFS 往往足够;而在网络路由、社交关系最短链路查找中,BFS 更为合适。

六、总结

深度优先搜索是图算法的基石之一。通过简单的 from 数组回溯机制,我们就能轻松实现路径查找功能。虽然它无法像 Dijkstra 或 A*那样处理加权图的最短路径问题,但其实现的简洁性和通用性使其成为学习更复杂算法前的最佳入门实践。掌握这一算法,有助于进一步理解图论中的连通性、拓扑排序等高级概念。

目录

  1. 图论寻路算法:深度优先搜索 (DFS) 实现
  2. 一、算法核心思想
  3. 数据结构设计
  4. 二、代码实现详解
  5. 1. 核心数据结构定义
  6. 2. DFS 遍历逻辑
  7. 3. 路径查询与展示
  8. 三、测试与应用
  9. 四、算法分析与优化
  10. 时间复杂度
  11. 空间复杂度
  12. 优化方向
  13. 五、DFS 与 BFS 对比
  14. 六、总结

更多推荐文章

查看全部
  • 基于 OpenClaw 与飞书构建 AI 新闻推送机器人
  • 基于本地大语言模型与 LangChain 构建免费 AI 搜索问答助手
  • 基于 Jetson 与 OpenClaw 搭建飞书远程交互系统
  • C# WinForm 调用 HeyGem 核心算法 DLL 封装实践
  • C++ 二叉搜索树:原理与增删查实现详解
  • Llama-Factory 集成 Wandb 监控:跨团队训练协作
  • 基于 Spring Boot 3 与 Vue 3 的汽车租赁系统
  • Web 虚拟卡销售平台实现方案
  • SenseVoiceSmall 语音识别 WebUI 快速部署与使用指南
  • MicroG 在 HarmonyOS 上的签名兼容方案与配置指南
  • Processing.py Python 创意编程入门指南
  • JavaEE 深度解析:从 Jakarta EE 演进、B/S 架构到 SSM 框架
  • 通义万相 2.1 结合计算平台实现 AIGC 内容生成
  • 基于 DeepFace 与 OpenCV 的实时情绪分析器实战
  • Linux 进程优先级详解:调度规则与调整方法
  • 基于 Vue 3 构建 imToken 风格钱包交互原型及核心流程验证
  • VSCode 常用 AI 编程助手插件推荐与实战
  • Java AI 项目开发实战:智能体 RAG SAA MCP 与大模型对接
  • WPF 中使用 TreeView 封装组合控件 TreeView+DataGrid
  • C语言数据结构与算法基础:文件操作、排序查找及链表简介

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

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

  • Gemini 图片去水印

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