算法——结合实例了解深度优先搜索(DFS)

news2025/2/22 18:53:58

一,深度优先搜索(DFS)详解

DFS是什么?

深度优先搜索(Depth-First Search,DFS)是一种用于遍历或搜索树、图的算法。其核心思想是尽可能深地探索分支,直到无法继续时回溯到上一个节点,尝试其他分支。DFS的实现通常基于递归或**栈(后进先出)**结构,适合解决路径存在性、状态可达性问题,但不保证找到最短路径。

与BFS的区别

  • BFS逐层展开,适合找最短路径。
  • DFS沿单一分支深入,可能更快找到解,但路径不一定最短。

DFS实现步骤

以递归实现为例,步骤如下:

  1. 终止条件:检查当前节点是否为目标(如到达终点)。
  2. 标记访问:将当前节点标记为已访问,避免重复处理。
  3. 递归探索:遍历当前节点的所有相邻节点,对未访问的节点递归调用DFS。

栈实现步骤

  1. 将起始节点压入栈。
  2. 循环执行以下操作直到栈空:
    • 弹出栈顶节点。
    • 若未访问,标记为已访问并处理。
    • 将该节点的未访问相邻节点压入栈。

注意事项

1. 剪枝优化

在深度优先搜索中,剪枝是一种非常重要的优化策略。它的核心思想是在搜索过程中,判断某些路径是否不可能到达终点,如果确定不可能,则提前终止对这条路径的搜索,从而减少不必要的计算量,提高搜索效率 。以走迷宫为例,假设我们在迷宫中搜索从起点到终点的路径,当我们走到某个位置时,通过计算发现从这个位置无论怎么走,剩余的步数都无法到达终点(比如剩余的步数小于从当前位置到终点的曼哈顿距离),那么就可以直接放弃对这个位置后续路径的搜索 ,这就是一种简单的剪枝操作。再比如,在一个复杂的迷宫中,如果我们已经走过了一条很长的死胡同,那么当再次遇到类似的路径开头时,就可以直接判断这条路径很可能也是死胡同,从而提前剪枝 。剪枝可以大大减少搜索的空间和时间复杂度,尤其是在处理大规模问题时,效果更为显著 。

2. 避免重复访问

在 DFS 中,标记已访问节点是至关重要的。如果不标记已访问节点,当搜索到一个节点时,可能会不断地重复访问它,从而陷入死循环 。比如在一个图结构中,如果存在环,不标记已访问节点就会导致在环上无限循环 。为了避免这种情况,我们通常使用一个数组或集合来记录节点的访问状态 。在走迷宫的例子中,我们使用二维布尔数组visited来记录每个位置是否被访问过 ,当访问一个新位置时,首先检查visited数组中对应位置的值,如果为true,则说明该位置已经被访问过,不再进行处理;如果为false,则将其标记为true,并继续进行搜索 。在处理图的 DFS 时,也可以使用一个哈希集合来记录已访问的节点,这样可以快速判断一个节点是否已经被访问过 。避免重复访问不仅可以防止死循环,还可以提高搜索效率,因为不需要对已经访问过的节点进行重复处理 。

3. 边界条件处理

在实现 DFS 时,仔细考虑边界条件是确保程序正确性和稳定性的关键 。边界条件包括节点超出范围、数组越界等情况 。以走迷宫为例,在判断一个位置是否可以访问时,需要检查该位置的坐标是否在迷宫的范围内 。如果迷宫是一个n * m的二维数组,那么位置(x, y)必须满足0 <= x < n且0 <= y < m,否则就超出了边界 。在马走日的例子中,当计算马的下一步位置时,同样要检查新位置是否在棋盘内 。如果不处理这些边界条件,程序可能会访问到非法的内存位置,导致运行时错误,如数组越界异常等 。因此,在编写 DFS 代码时,一定要在递归调用之前,仔细检查边界条件,确保程序的健壮性 。


二,实例解析

实例1:中国象棋中马的日字形移动

在这里插入图片描述

问题描述
马从起点 (x, y) 出发,按“日”字形移动(横向±1且纵向±2,或横向±2且纵向±1),判断能否到达目标点 (tx, ty),并统计路径数。

DFS实现步骤

  1. 定义方向:8种可能的移动方向:
    directions = [ (2,1), (1,2), (-1,2), (-2,1),
                   (-2,-1), (-1,-2), (1,-2), (2,-1) ]
    
  2. 递归终止条件:当前位置等于目标位置时返回成功。
  3. 遍历所有方向:对每个方向计算新位置 (nx, ny),检查是否在棋盘内且未访问。
  4. 回溯恢复状态:递归返回后,将当前位置标记为未访问,以允许其他路径经过。

示例代码(伪代码)

def dfs(x, y, visited, target):
    if (x, y) == target:
        return 1  # 找到一条路径
    count = 0
    visited[x][y] = True
    for dx, dy in directions:
        nx, ny = x + dx, y + dy
        if 0 <= nx < 8 and 0 <= ny < 8 and not visited[nx][ny]:
            count += dfs(nx, ny, visited, target)
    visited[x][y] = False  # 回溯
    return count

实例2:走迷宫

在这里插入图片描述

问题描述
从迷宫起点 (0, 0) 出发,寻找一条到达终点 (m-1, n-1) 的路径。迷宫用二维数组 grid 表示,0 为通路,1 为墙。

DFS实现步骤

  1. 定义方向:上下左右四个移动方向。
    directions = [ (-1,0), (1,0), (0,-1), (0,1) ]
    
  2. 递归终止条件:当前位置为终点时记录路径。
  3. 剪枝无效路径:跳过越界、撞墙或已访问的位置。
  4. 回溯恢复状态:递归返回后,将当前位置标记为未访问。

示例代码(伪代码)

def dfs(x, y, path, visited):
    if (x, y) == (m-1, n-1):
        print(path)
        return
    for dx, dy in directions:
        nx, ny = x + dx, y + dy
        if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == 0 and not visited[nx][ny]:
            visited[nx][ny] = True
            path.append((nx, ny))
            dfs(nx, ny, path, visited)
            path.pop()
            visited[nx][ny] = False

总结与期望

在这里插入图片描述
深度优先搜索作为一种基础且强大的搜索算法,在解决各类路径搜索问题中展现出独特的优势。通过马走日和走迷宫这两个实例,我们深入理解了 DFS 的工作原理、实现步骤以及在实际应用中的注意事项 。在马走日的问题中,我们利用 DFS 探索马在棋盘上的所有可能移动路径,计算遍历整个棋盘的途径总数,这体现了 DFS 在处理具有特定规则的移动和状态空间搜索问题上的有效性 。而在走迷宫的场景里,DFS 帮助我们从起点出发,通过不断探索和回溯,寻找通往终点的路径,展示了其在解决复杂空间搜索问题的能力 。

DFS 的核心在于递归探索和回溯机制,这使得它能够全面地搜索所有可能的路径。同时,剪枝优化、避免重复访问和边界条件处理等注意事项,对于提高 DFS 的效率和正确性至关重要 。在未来的学习和实践中,我们可以进一步探索 DFS 在更复杂场景下的应用,比如在图论中寻找连通分量、检测环路等问题 。此外,将 DFS 与其他算法相结合,如与启发式搜索算法结合,可能会产生更高效的解决方案 。随着计算机技术的不断发展,DFS 在人工智能、游戏开发、网络分析等领域的应用前景也将更加广阔 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2298014.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringMVC学习使用

一、SpringMVC简单理解 1.1 Spring与Web环境集成 1.1.1 ApplicationContext应用上下文获取方式 应用上下文对象是通过new ClasspathXmlApplicationContext(spring配置文件) 方式获取的&#xff0c;但是每次从容器中获得Bean时都要编写new ClasspathXmlApplicationContext(sp…

运维-自动访问系统并截图

需求背景 因项目甲方要求需要对系统进行巡检&#xff0c;由于系统服务器较多&#xff0c;并且已经采用PrometheusGrafana对系统服务器进行管理&#xff0c;如果要完成该任务&#xff0c;需要安排一个人力对各个系统和服务器进行一一截图等操作&#xff0c;费时费力&#xff0c…

在CodeBlocks搭建SDL2工程虚拟TFT彩屏解码带压缩形式的Bitmap(BMP)图像显示

在CodeBlocks搭建SDL2工程虚拟TFT彩屏解码带压缩形式的Bitmap BMP图像显示 参考文章文章说明一、创建和退出SDL2二、 Bitmap(BMP)图片解码图三、Bitmap解码初始化四、测试代码五、主函数六、测试结果 参考文章 解码带压缩形式的Bitmap(BMP)图像并使用Python可视化解码后实际图…

mapbox进阶,添加绘图扩展插件,绘制任意方向矩形

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️MapboxDraw 绘图控件二、🍀添加绘图扩…

初阶c语言(循环语句习题,完结)

前言&#xff1a; c语言为b站鹏哥&#xff0c;嗯对应视频37集 昨天做的c语言&#xff0c;今天在来做一遍&#xff0c;发现做错了 今天改了平均值的计算&#xff0c; 就是说最大值加上最小值&#xff0c;如果说这个数值非常大的话&#xff0c;两个值加上会超过int类型的最大…

提升编程效率,体验智能编程助手—豆包MarsCode一键Apply功能测评

提升编程效率&#xff0c;体验智能编程助手—豆包MarsCode一键Apply功能测评 &#x1f31f; 嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 目录 引言豆包…

【deepseek-r1本地部署】

首先需要安装ollama,之前已经安装过了&#xff0c;这里不展示细节 在cmd中输入官网安装命令&#xff1a;ollama run deepseek-r1:32b&#xff0c;开始下载 出现success后&#xff0c;下载完成 接下来就可以使用了&#xff0c;不过是用cmd来运行使用 可以安装UI可视化界面&a…

多用户商城系统的客服管理体系建设

多用户商城系统的运营&#xff0c;客服管理体系建设至关重要。优质的客服服务不仅能提升用户购物体验&#xff0c;还能增强用户对商城的信任与忠诚度&#xff0c;进而促进商城业务的持续增长。以下从四个关键方面探讨如何建设完善的客服管理体系&#xff0c;信息化客服系统在其…

C++设计模式 - 模板模式

一&#xff1a;概述 模板方法&#xff08;Template Method&#xff09;是一种行为型设计模式。它定义了一个算法的基本框架&#xff0c;并且可能是《设计模式&#xff1a;可复用面向对象软件的基础》一书中最常用的设计模式之一。 模板方法的核心思想很容易理解。我们需要定义一…

CZML 格式详解,javascript加载导出CZML文件示例

示例地址&#xff1a;https://dajianshi.blog.csdn.net/article/details/145573994 CZML 格式详解 1. 什么是 CZML&#xff1f; CZML&#xff08;Cesium Zipped Markup Language&#xff09;是一种基于 JSON 的文件格式&#xff0c;用于描述地理空间数据和时间动态场景。它专…

OpenAI推出全新AI助手“Operator”:让人工智能帮你做事的新时代!

引言 随着人工智能技术的不断发展&#xff0c;OpenAI 再次推出令人兴奋的功能——Operator&#xff0c;一个全新的 AI 助手平台。这不仅仅是一个普通的助手&#xff0c;它代表了人工智能技术的又一次飞跃&#xff0c;将改变我们工作和生活的方式。 什么是“Operator”&#xff…

重看Spring聚焦BeanFactory分析

目录 一、理解BeanFactory &#xff08;一&#xff09;功能性理解 &#xff08;二&#xff09;BeanFactory和它的子接口 &#xff08;三&#xff09;BeanFactory的实现类 二、BeanFactory根接口 &#xff08;一&#xff09;源码展示和理解 &#xff08;二&#xff09;基…

将Docker容器打包成镜像提交

前言 Docker 是一个开源软件&#xff0c;也是一个开放平台&#xff0c;用于开发应用、交付&#xff08;shipping&#xff09;应用、运行应用。 Docker允许用户将基础设施&#xff08;Infrastructure&#xff09;中的应用单独分割出来&#xff0c;形成更小的颗粒&#xff08;容…

一文通俗理解为什么需要泛型以及泛型的使用

为什么需要泛型&#xff1f; public static void main(String[] args) {ArrayList list new ArrayList();// 由于集合没有做任何限定&#xff0c;任何类型都可以给其中存放list.add("abc");list.add("def");list.add(5);Iterator it list.iterator();wh…

Sam Altman 揭秘 OpenAI 未来蓝图:GPT-4.5、GPT-5 与模型规范重大更新

OpenAI CEO Sam Altman 近日在 X 平台&#xff08;原 Twitter&#xff09;上分享了关于 GPT-4.5 (代号 “Orion”) 和 GPT-5 的最新进展&#xff0c;同时公布了 OpenAI 模型规范&#xff08;Model Spec&#xff09;的重大更新&#xff0c;强调知识自由与模型行为准则。 核心亮…

老牌系统工具箱,现在还能打!

今天给大家分享一款超实用的电脑软硬件检测工具&#xff0c;虽然它是一款比较“资深”的软件&#xff0c;但依然非常好用&#xff0c;完全能满足我们的日常需求。 电脑软硬件维护检测工具 功能强大易用 这款软件非常贴心&#xff0c;完全不需要安装&#xff0c;直接打开就能用…

在vivado中对数据进行延时,时序对齐问题上的理清

在verilog的ISP处理流程中&#xff0c;在完成第一个模块的过程中&#xff0c;我经常感到困惑&#xff0c;到底是延时了多少个时钟&#xff1f;今日对这几个进行分类理解。 目录 1.输入信号激励源描述 1.1将数据延时[9]个clk 1.2将vtdc与hzdc延时[9]个clk(等价于单bit的数据…

链表 —— 常用技巧与操作总结详解

引言 链表作为一种动态数据结构&#xff0c;以其灵活的内存管理和高效的插入删除操作&#xff0c;在算法与工程实践中占据重要地位。然而&#xff0c;链表的指针操作复杂&#xff0c;容易引发内存泄漏和野指针问题。本文博主将从基础操作到高阶技巧&#xff0c;系统化解析链表的…

Linux下学【MySQL】常用函数助你成为数据库大师~(配sql+实操图+案例巩固 通俗易懂版~)

绪论​ 每日激励&#xff1a;“唯有努力&#xff0c;才能进步” 绪论​&#xff1a; 本章是MySQL中常见的函数&#xff0c;利用好函数能很大的帮助我们提高MySQL使用效率&#xff0c;也能很好处理一些情况&#xff0c;如字符串的拼接&#xff0c;字符串的获取&#xff0c;进制…

[c语言日寄]在不完全递增序中查找特定要素

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋&#xff1a;这是一个专注于C语言刷题的专栏&#xff0c;精选题目&#xff0c;搭配详细题解、拓展算法。从基础语法到复杂算法&#xff0c;题目涉及的知识点全面覆盖&#xff0c;助力你系统提升。无论你是初学者&#xff0c;还是…