深度优先搜索与广度优先搜索,你知道它们的区别吗?

什么是深度优先搜索?

深度优先搜索(DFS,Depth-First Search)是算法中的一种重要的搜索策略。它的核心思想是“深入探索,直至无路可走,然后再回溯”。这种策略在许多问题中都有着广泛的应用,例如图的遍历、路径查找、解决迷宫问题等等。

让我们通过一个生活中的例子来理解深度优先搜索。假设你正在玩一个迷宫游戏,你需要从迷宫的入口找到出口。你可以选择往前走,直到遇到死胡同,然后再回头,选择另外一个方向继续前进,直到找到出口。这个过程,就是深度优先搜索的一个形象展现。

深度优先搜索的过程就像是在一条路上不断探索,直到这条路走不通,然后再回溯,寻找其他的路。这种策略虽然可能会让我们走一些冤枉路,但它却能保证我们遍历到每一个可能的路口,不会漏掉任何一个可能的解决方案。

明白了深度优先搜索的基本概念和核心思想后,接下来我们将学习如何通过编程实现这种搜索策略。

深度优先搜索的实现

深度优先搜索的实现并不复杂,但却需要我们对递归或栈有深入的理解。下面,让我们通过一个Java代码示例来了解如何实现深度优先搜索。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class OneMoreClass {

    // 用于标记节点是否被访问过 
    private Map<Integer, Boolean> visited = new HashMap<>();

    // 邻接表表示的图 
    private Map<Integer, List<Integer>> graph = new HashMap<>();

    /**
     * 添加边
     *
     * @param u 起点
     * @param v 终点
     */
    public void addEdge(int u, int v) {
        // 初始化邻接表 
        if (!graph.containsKey(u)) {
            graph.put(u, new ArrayList<>());
            visited.put(u, false);
        }
        if (!graph.containsKey(v)) {
            graph.put(v, new ArrayList<>());
            visited.put(v, false);
        }
        // 在u的邻接表中添加v 
        graph.get(u).add(v);
    }

    /**
     * 深度优先搜索
     *
     * @param v 当前访问的节点
     */
    public void dfs(int v) {
        // 标记当前节点已访问 
        visited.put(v, true);
        System.out.print(v + " ");

        // 访问v的所有未被访问过的邻居节点 
        for (int neighbor : graph.get(v)) {
            if (!visited.get(neighbor)) {
                dfs(neighbor);
            }
        }
    }

    public static void main(String[] args) {
        OneMoreClass dfs = new OneMoreClass();
        dfs.addEdge(0, 1);
        dfs.addEdge(0, 2);
        dfs.addEdge(1, 2);
        dfs.addEdge(2, 0);
        dfs.addEdge(2, 3);
        dfs.addEdge(3, 3);

        System.out.println("深度优先搜索(从节点2开始):");
        dfs.dfs(2);
    }
}

在这个例子中,我们首先定义了一个图,然后通过深度优先搜索遍历了这个图。我们使用邻接表来表示图,并使用一个HashMap来记录每个节点是否被访问过。在深度优先搜索中,我们首先访问一个节点,然后递归地访问它的所有未被访问过的邻居节点。运行结果如下:

深度优先搜索(从节点2开始):
2 0 1 3

这段代码虽然简短,但却包含了深度优先搜索的核心思想。通过递归,我们可以轻松地实现深度优先搜索,遍历所有的节点。

然而,深度优先搜索并非没有问题。在实际使用中,我们可能会遇到一些问题,例如递归深度过大导致的栈溢出问题,或者是非递归实现时栈的使用不当等。接下来,让我们来了解一下广度优先搜索。

什么是广度优先搜索?

在深入浸润了深度优先搜索的世界之后,我们来到了另一个重要的概念——广度优先搜索。如果说深度优先搜索是一种勇敢的冒险者,深入洞穴的每一个角落,那么广度优先搜索则像是一位细心的园丁,逐层照顾每一朵花儿,不让任何一处被忽视。

广度优先搜索(Breadth-First Search,BFS)是一种在树(Tree)或图(Graph)这样的数据结构中进行搜索的算法。它的特点是一层一层地进行搜索,每一层的节点都会被访问到,然后再进入下一层。这种方式就好比我们在寻找某个城市的地铁站,先从起点站开始,然后逐站寻找,直到找到目标站为止。

接下来,我们将深入探讨如何实现广度优先搜索,以及在实际应用中如何使用它来解决问题。

广度优先搜索的实现

在深入理解了广度优先搜索的基本概念之后,让我们一起来探讨如何用Java语言将其实现。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

public class OneMoreClass {

    // 用于标记节点是否被访问过 
    private Map<Integer, Boolean> visited = new HashMap<>();

    // 邻接表表示的图 
    private Map<Integer, List<Integer>> graph = new HashMap<>();

    /**
     * 添加边
     *
     * @param u 起点
     * @param v 终点
     */
    public void addEdge(int u, int v) {
        // 初始化邻接表 
        if (!graph.containsKey(u)) {
            graph.put(u, new ArrayList<>());
            visited.put(u, false);
        }
        if (!graph.containsKey(v)) {
            graph.put(v, new ArrayList<>());
            visited.put(v, false);
        }
        // 在u的邻接表中添加v 
        graph.get(u).add(v);
    }

    /**
     * 广度优先搜索
     *
     * @param v 当前访问的节点
     */
    public void bfs(int v) {
        // 创建一个队列,用于存储待访问的节点 
        Queue<Integer> queue = new LinkedList<>();
        queue.add(v);
        visited.put(v, true);

        while (!queue.isEmpty()) {
            int node = queue.poll();
            System.out.print(node + " ");

            // 访问node的所有未被访问过的邻居节点 
            for (int neighbor : graph.get(node)) {
                if (!visited.get(neighbor)) {
                    queue.add(neighbor);
                    visited.put(neighbor, true);
                }
            }
        }
    }

    public static void main(String[] args) {
        OneMoreClass bfs = new OneMoreClass();
        bfs.addEdge(0, 1);
        bfs.addEdge(0, 2);
        bfs.addEdge(1, 2);
        bfs.addEdge(2, 0);
        bfs.addEdge(2, 3);
        bfs.addEdge(3, 3);

        System.out.println("广度优先搜索(从节点2开始):");
        bfs.bfs(2);
    }
}

我们使用了一个队列来存储待访问的节点,而不是直接递归访问。这是因为广度优先搜索是按照距离顺序访问节点的,即先访问距离当前节点最近的节点,然后再访问距离当前节点稍远一些的节点,以此类推。运行结果如下:

广度优先搜索(从节点2开始):
2 0 3 1

这种实现方式看似简单,但其中蕴含的深度却不容忽视。在实际应用中,我们可能会遇到各种各样的问题,比如如何处理图中的环,如何优化搜索效率等等。

深度优先搜索与广度优先搜索的比较

在我们深入了解深度优先搜索和广度优先搜索的特性后,现在我们来比较一下这两种搜索策略的优缺点,以及它们在不同场景下的应用。

深度优先搜索,如同其名,它的特点是尽可能深地搜索树的分支。这种策略在搜索大树时非常有效,因为它可以快速找到解决方案,或者在没有解决方案的情况下,快速排除某些路径。然而,这种策略也有其局限性,例如,它可能会在搜索过程中陷入无限循环。为了避免这种情况,我们通常需要在实现深度优先搜索时,加入一些特殊的检查机制。

广度优先搜索则是一种层次遍历的策略,它会先搜索离根节点最近的节点,然后再搜索下一层的节点。这种策略在搜索最短路径问题时非常有效,因为它总是先搜索离根节点最近的路径,所以一旦找到解决方案,那么这个解决方案就是最短的。然而,广度优先搜索需要存储所有的节点,因此在空间复杂度上,通常会比深度优先搜索要大。

让我们通过一个实际的例子来理解这两种搜索策略。假设我们想要找到从A地点到B地点的路线。如果我们使用深度优先搜索,那么我们可能会先找到一条从A到B的路线,但这条路线可能不是最短的。如果我们使用广度优先搜索,我们会先找到所有从A出发可以到达的地点,然后再从这些地点出发,找到可以到达B的地点。这样,我们找到的第一条路线,就是最短的路线。

在实际的应用中,我们应该根据问题的特性,选择最适合的搜索策略。例如,如果我们需要找到所有可能的解决方案,那么深度优先搜索可能会更有效。而如果我们需要找到最短的解决方案,那么广度优先搜索可能会更合适。

总结

我们深入探讨了深度优先搜索和广度优先搜索,这两种广泛应用的搜索策略。我们通过生动的例子和简单的代码示例,理解了它们的基本概念,实现方法,以及在实际问题中的应用。

深度优先搜索和广度优先搜索,就如同我们生活中的两种不同的决策策略。深度优先搜索,就像是一位勇敢的冒险家,愿意深入探索未知的世界,即使可能会走一些冤枉路,也不愿意错过任何一个可能的机会。而广度优先搜索,就像是一位谨慎的规划者,他会仔细地考虑每一步的选择,以最高的效率,找到最优的解决方案。

深度优先搜索和广度优先搜索是我们解决问题的重要工具。但是,我们不能盲目地选择使用哪一种搜索策略,而应该根据问题的特性,选择最适合的策略。这就像我们在生活中面临选择时,不能盲目地跟随别人,而应该根据自己的情况,做出最适合自己的决定。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

telnet 退出失败ctrl+c

1. 使用ctrl] &#xff0c;退出到telnet >界面 2. quit 或者 3. 直接强制退出&#xff1a; ] Enter键

第十五届蓝桥杯省赛第二场C/C++B组F题【狡兔k窟】题解(AC)

题意分析 有一个 n n n 个点&#xff0c; n − 1 n-1 n−1 条边的无向图&#xff0c;边权均为 1 1 1。 每个点隶属于一个集合&#xff0c;同一个集合的点可以互相传送。 给定 m m m 个询问&#xff0c;求 x , y x, y x,y 的最短距离。 最短路解法 步骤&#xff1a; 建…

探索数学语言模型的前沿进展——人工智能在数学教育和研究中的应用

数学一直被认为是科学的基石&#xff0c;对于推动技术进步和解决现实世界问题具有重要意义。然而&#xff0c;传统的数学问题解决方式正面临着数字化转型的挑战。MLMs的出现&#xff0c;预示着数学学习和研究方式的一次革命。 MLMs&#xff0c;包括预训练语言模型&#xff08;…

黑马-设计模式-笔记(未完)

一、基础 UML类图 可见性&#xff1a; public- private#protected 表示方式&#xff1a;属性&#xff1a;可见性 名称:类型[默认值]方法&#xff1a;可见性 名称(参数)[:返回类型] 关系&#xff1a;关联关系&#xff1a;实线&#xff0c;引用关系&#xff0c;类属性里有另一个…

CUDA的应用场景

CUDA的应用场景随着技术的发展不断扩展&#xff0c;其核心优势在于能够显著提高并行计算任务的处理速度&#xff0c;这对于任何需要处理大量数据和执行复杂计算的领域都是极其有价值的。CUDA开发的应用场景非常广泛&#xff0c;主要得益于其强大的并行计算能力&#xff0c;以下…

【软考】UML中的关系

目录 1. 说明2. 依赖3. 关联4. 泛化5. 实现 1. 说明 1.UML中有4种关系&#xff1a;依赖、关联、泛化和实现2.这 4种关系是 UML,模型中可以包含的基本关系事物。它们也有变体&#xff0c;例如&#xff0c;依赖的变体有精化、跟踪、包含和延伸 2. 依赖 1.依赖(Dependency)。2.…

代码随想录刷题随记27-贪心1

代码随想录刷题随记27-贪心 455.分发饼干 leetcode链接 class Solution {public int findContentChildren(int[] g, int[] s) {//boolean used[]new boolean [s.length];Arrays.sort(s);Arrays.sort(g);int index0;int ret0;for(int i0;i<g.length;i){while(index<s.…

MySQL--表的操作

目录 创建表 查看表结构 修改表 新增列 修改列类型 修改列名 修改表名&#xff1a; 删除列 删除表 创建表 语法&#xff1a; CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引…

【Entity Framework】聊一聊EF如何使用数据库函数

【Entity Framework】聊一聊EF如何使用数据库函数 文章目录 【Entity Framework】聊一聊EF如何使用数据库函数一、数据库函数的类型二、内置函数与用户定义的函数四、聚合函数、标量函数和表值函数五、Niladic函数六、EF Core 中的数据库函数映射6.1 内置函数映射6.2 EF.Functi…

请编写一个函数void fun(char*ss),其功能是:将字符串ss中所有下标为奇数位置上的字母转换为大写(若该位置上不是字母,则不转换)。

本文收录于专栏:算法之翼 https://blog.csdn.net/weixin_52908342/category_10943144.html 订阅后本专栏全部文章可见。 本文含有题目的题干、解题思路、解题思路、解题代码、代码解析。本文分别包含C语言、C++、Java、Python四种语言的解法完整代码和详细的解析。 题干 请编…

mPEG-Dansyl,Methoxy PEG Dansyl由甲氧基-聚乙二醇(mPEG)和丹磺酰氯(Dansyl)两部分组成

【试剂详情】 英文名称 mPEG-Dansyl&#xff0c;Methoxy PEG Dansyl 中文名称 聚乙二醇单甲醚丹磺酸酯&#xff0c;甲氧基-聚乙二醇-丹磺酰胺 外观性状 由分子量决定&#xff0c;液体或者固体 分子量 0.4k&#xff0c;0.6k&#xff0c;1k&#xff0c;2k&#xff0c;3.4k…

Fisher 准则分类

目录 一、什么是Fisher 准则 二、具体实例 三、代码实现 四、结果 一、什么是Fisher 准则 Fisher准则&#xff0c;即Fisher判别准则&#xff08;Fisher Discriminant Criterion&#xff09;&#xff0c;是统计学和机器学习中常用的一种分类方法&#xff0c;由统计学家罗纳…

JuliaImages教程(二):图像分割

1、介绍 图像分割是将图像划分为具有相似属性的区域的过程。图像分割具有多种应用&#xff0c;例如医学图像分割、图像压缩&#xff0c;并用作对象检测和光流等更高级别视觉任务中的预处理步骤。该包是用 Julia 编写的图像分割算法的集合。 2、安装 Pkg.add("ImageSegm…

软件测试面试题(二)

Web 测试.web 测试描述用浏览器访问 www.baidu.com 的过程以京东首页为例&#xff0c;设计用例框架。&#xff08;注意框架设计逻辑&#xff0c;区域划分&#xff0c;专项测试等&#xff0c;不需 要详细用例&#xff0c;需要查看 PC 可直接和辨识管提要求&#xff09;如何测试购…

Java Web 网页设计(1)

不要让追求之舟停泊在幻想的港湾 而应扬起奋斗的风帆 驶向现实生活的大海 网页设计 1.首先 添加框架支持 找到目录右键添加 找到Web Application选中 点击OK 然后 编辑设置 找到Tomcat--local 选中 点击OK 名称可以自己设置 找到对应文件夹路径 把Tomcat添加到项目里面 因为…

C++之通俗易懂学模版

目录 一、了解什么是泛性编程 二、模版 1.函数模版 1.1 函数模板概念 1.2 函数模板格式 1.3 函数模板的原理 1.4 函数模板的实例化 1.5 模板参数的匹配原则 2.类模板 2.1 类模板的定义格式 2.2 类模板的实例化 3. 非类型模板参数 4. 模板的特化 4.1 概念 4.2 …

Visual Studio调试C/C++指南

1. 前言 Visual Studio&#xff08;VS&#xff09;是微软开发的一款集成开发环境(IDE)软件&#xff0c;支持C/C、C#、VB、Python等开发语言&#xff0c;开发桌面、Web等应用程序。VS功能极其强大&#xff0c;使用极其便利&#xff0c;用户数量最多&#xff0c;被誉为"宇宙…

Python 基础 (Pandas):Pandas 入门

1. 官方文档 API reference — pandas 2.2.2 documentation 2. 准备知识&#xff1a;Pandas 数据结构 Series & DataFrame 2.1 Series 2.1.1 创建 Series 类型数据 一个 Series 对象包含两部分&#xff1a;值序列、标识符序列。可通过 .values (返回 NumPy ndarry 类型…

C语言扫雷游戏完整实现(下)

文章目录 前言一、排雷函数菜单二、排雷函数菜单的实现三、拓展棋盘功能四、源码1. test.c源文件2. game.h头文件3. game.c源文件 总结 前言 C语言实现扫雷游戏的排雷菜单&#xff0c;以及功能的实现&#xff0c;拓展棋盘功能&#xff0c;以及源码等。 上半部分的链接地址: C语…

第十五届蓝桥杯省赛第二场PythonB组B题【逆序对期望】题解(AC)

解题思路 枚举所有的可能的交换情况&#xff0c;时间复杂度 O ( n 4 ) O(n^4) O(n4)。 用归并排序计算数组的逆序对&#xff0c;时间复杂度 O ( n ) O(n) O(n)。 综上时间复杂度 O ( n 5 ) O(n^5) O(n5)。 由于 Python 运行效率较低&#xff0c;约 500 500 500 秒可得到…