数据结构与算法——广度和深度优先搜索

简介: 前面说到了图这种非线性的数据结构,并且我使用了代码,简单演示了图是如何实现的。今天就来看看基于图的两种搜索算法,分别是广度优先搜索和深度优先搜索算法,这两个算法都十分的常见,在平常的面试当中也可能遇到。

1. 概论


前面说到了图这种非线性的数据结构,并且我使用了代码,简单演示了图是如何实现的。今天就来看看基于图的两种搜索算法,分别是广度优先搜索和深度优先搜索算法,这两个

算法都十分的常见,在平常的面试当中也可能遇到。


在图上面的搜索算法,其实主要的表现形式就是从图中的一个顶点,找到和另一个顶点之间的路径,而两种搜索算法,都是解决这个问题的。


2. 广度优先搜索


广度优先搜索的基本思路就是从一个顶点出发,层层遍历,直到找到目标顶点,其实这样搜索出来的路径也就是两个顶点之间的最短距离。如下图所示,例如要搜索出顶点 s -> t 的路径,搜索的方式就是这样的:

其中黄色的线条表示搜索的节点,数字 1、2、3、4 表示搜索的次序,广度优先搜索的原理看起来十分的简单,但是它的代码实现还是稍微有点难的,先来看看整体的代码实现,然后再具体讲解一下:

public class BFS {
    /**
     * 广度优先搜索算法
     * @param graph 图
     * @param s 搜索的起点(对应图中的一个顶点)
     * @param t 搜索的终点
     */
    public static void bfs(Graph graph, int s, int t){
        if (s == t) return;
        //获得图的顶点个数
        int vertex = graph.getVertex();
        //获取存储图顶点的列表
        LinkedList<Integer>[] list = graph.getList();
        //如果某个顶点已经被访问,则设置为true
        boolean[] visited = new boolean[vertex];
        visited[s] = true;
        //队列,存储的是已经被访问,但是其相连的顶点还没有被访问的顶点
        Queue<Integer> queue = new LinkedList<>();
        queue.add(s);
        //记录搜索的路径
        int[] path = new int[vertex];
        for (int i = 0; i < vertex; i++) {
            path[i] = -1;
        }
        while (queue.size() != 0){
            int w = queue.poll();
            for (int i = 0; i < list[w].size(); i++) {
                int q = list[w].get(i);
                if (!visited[q]){
                    path[q] = w;
                    if (q == t){
                        print(path, s, t);
                        return;
                    }
                    visited[q] = true;
                    queue.add(q);
                }
            }
        }
    }
    //递归打印 s-t 的路径
    private static void print(int[] prev, int s, int t){
        if (prev[t] != -1 && t != s){
            print(prev, s, prev[t]);
        }
        System.out.print(t + " ");
    }
}

程序中有三个辅助的变量:

一是 boolean[] visited ,这个数组表示如果已经被访问,则设置为 true,例如顶点 s,是最开始被访问的,直接设置为 true。

二是有一个队列 queue,它表示的是,一个顶点已经被访问,但是其相邻的顶点还没有被访问的顶点。例如顶点 s,它自己被访问了,但是和它相邻的两个顶点还没有被访问,因此直接被添加到了队列当中。

三是数组 path,它表示一个顶点是被哪个顶点所访问的,数组下标表示的是顶点,对应存储的是由谁所访问。这个逻辑在代码中的体现便是 path[q] = w 这一行。最后,这个数组中存储的便是搜索的路径,需要递归打印出来。


3. 深度优先搜索


再来看看深度优先搜索,这种搜索的基本思路就是:从起始顶点出发,任意遍历顶点,如果走不通,则回退一个顶点,然后换一个顶点继续遍历,知道找到目标顶点。像下图这样:

图中从顶点 s 出发,蓝色的表示前进的顶点,红色的表示后退一个顶点,直到找到目标顶点 t,相信你可以看出来,这样搜索出来的路径其实并不是 s 到 t 的最短路径,而是任意的一条路径。

深度优先的代码实现:

public class DFS {
    //判断是否找到了目标顶点
    private static boolean found =  false;
    public static void dfs(Graph graph, int s, int t){
        int vertex = graph.getVertex();
        boolean[] visited = new boolean[vertex];
        int[] path = new int[vertex];
        for (int i = 0; i < vertex; i++) {
            path[i] = -1;
        }
        LinkedList<Integer>[] list = graph.getList();
        recursionDfs(list, s, t, visited, path);
        print(path, s, t);
    }
    //递归遍历
    private static void recursionDfs(LinkedList<Integer>[] list, int w, int t, boolean[] visited, int[] path){
        if (found) return;
        visited[w] = true;
        if (w == t){
            found = true;
            return;
        }
        for (int i = 0; i < list[w].size(); i++) {
            int q = list[w].get(i);
            if (!visited[q]){
                path[q] = w;
                recursionDfs(list, q, t, visited, path);
            }
        }
    }
    private static void print(int[] path, int s, int t){
        if (path[t] != -1 && t != s){
            print(path, s, path[t]);
        }
        System.out.print(t + " ");
    }
}

变量 boolean[] visited 和广度优先搜索一样,都是表示访问过的节点设置为 true,path 数组表示访问的路径。

最后,总结一下,广度和深度优先搜索,都是比较暴力的搜索方式,没有什么优化,层层遍历或者一路递归,所以不难看出,这两个算法的时间复杂度接近 O(n),空间复杂度也是 O(n),还是稍微有点高的,所以这两种搜索算法适用于图上的顶点数据不太多的情况。

相关文章
|
2月前
|
算法 测试技术 定位技术
数据结构与算法——DFS(深度优先搜索)
数据结构与算法——DFS(深度优先搜索)
|
1月前
|
算法 安全 网络安全
数据结构之网络攻击路径(深度优先搜索)
本文介绍了如何使用深度优先搜索(DFS)算法分析网络攻击路径。在网络安全领域,DFS用于检测网络中潜在的攻击路径,帮助安全人员及时发现并阻止威胁。文中详细描述了网络图的构建、节点间的连接关系以及DFS的实现过程。通过一个具体的例子,展示了如何检测从一个普通节点到关键节点的攻击路径,并讨论了DFS算法的优缺点。提供的C++代码实现了网络图的构建和攻击路径的检测功能。
67 24
|
1月前
|
算法
数据结构之博弈树搜索(深度优先搜索)
本文介绍了使用深度优先搜索(DFS)算法在二叉树中执行遍历及构建链表的过程。首先定义了二叉树节点`TreeNode`和链表节点`ListNode`的结构体。通过递归函数`dfs`实现了二叉树的深度优先遍历,按预序(根、左、右)输出节点值。接着,通过`buildLinkedList`函数根据DFS遍历的顺序构建了一个单链表,展示了如何将树结构转换为线性结构。最后,讨论了此算法的优点,如实现简单和内存效率高,同时也指出了潜在的内存管理问题,并分析了算法的时间复杂度。
52 0
|
1月前
|
算法
数据结构之路由表查找算法(深度优先搜索和宽度优先搜索)
在网络通信中,路由表用于指导数据包的传输路径。本文介绍了两种常用的路由表查找算法——深度优先算法(DFS)和宽度优先算法(BFS)。DFS使用栈实现,适合路径问题;BFS使用队列,保证找到最短路径。两者均能有效查找路由信息,但适用场景不同,需根据具体需求选择。文中还提供了这两种算法的核心代码及测试结果,验证了算法的有效性。
102 23
|
1月前
|
传感器 算法
数据结构之环境监测系统(深度优先搜索)
环境监测系统采用深度优先搜索(DFS)算法,实现实时监测和分析环境参数,如温度、湿度等。系统通过构建传感器网络图结构,利用DFS遍历网络,检测异常数据。当温度超过预设阈值时,系统将发出警告。此系统适用于工业生产、室内空调控制、农业温室管理等多种场景,提供高效的环境监测解决方案。
49 12
|
1月前
|
算法
数据结构之旅行商问题(深度优先搜索)
旅行商问题(TSP)是寻找访问多个城市并返回起点的最短路径的经典问题。本文介绍了TSP的背景、应用、复杂性和解决方法,重点讲解了使用深度优先搜索(DFS)算法求解TSP的过程。通过邻接矩阵表示城市间的距离,利用访问数组和栈结构辅助DFS遍历,最终找到最优路径。此方法虽然能保证找到最优解,但时间复杂度高,适用于城市数量较少的情况。示例代码展示了算法的具体实现及结果分析。
49 2
|
1月前
|
算法
数据结构之农业作物管理(深度优先搜索)
本文探讨了农业作物管理系统的背景、发展动因及其在现代农业中的重要性,特别是在应对气候变化、资源减少等挑战时的作用。文中介绍了作物关系建模与深度优先搜索(DFS)的应用,展示了如何通过邻接矩阵和DFS算法实现作物的智能管理和优化。通过具体的数据结构设计和核心代码实现,说明了DFS在农业作物管理中的应用效果及优缺点。
37 1
|
2月前
|
算法 C++
【算法解题思想】动态规划+深度优先搜索(C/C++)
【算法解题思想】动态规划+深度优先搜索(C/C++)
|
6月前
|
Python
求解带有限重的三维装箱问题——启发式深度优先搜索算法
求解带有限重的三维装箱问题——启发式深度优先搜索算法
123 4

热门文章

最新文章

  • 1
    2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
    30
  • 2
    2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    27
  • 3
    2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    29
  • 4
    2024重生之回溯数据结构与算法系列学习(8)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    31
  • 5
    2024重生之回溯数据结构与算法系列学习之王道第2.3章节之线性表精题汇总二(5)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    25
  • 6
    2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    39
  • 7
    2024重生之回溯数据结构与算法系列学习之顺序表习题精讲【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    26
  • 8
    2024重生之回溯数据结构与算法系列学习之顺序表【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    33
  • 9
    2024重生之回溯数据结构与算法系列学习【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    25
  • 10
    数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
    95