首页 > 其他分享 >深入探索:深度优先遍历与广度优先遍历的奥秘与应用

深入探索:深度优先遍历与广度优先遍历的奥秘与应用

时间:2024-09-20 22:20:36浏览次数:12  
标签:优先 遍历 graph DFS addEdge BFS 广度 节点

在算法和数据结构的广阔领域中,图的遍历是一个核心且基础的概念,它支撑着众多高级算法和应用的实现。深度优先遍历(DFS)和广度优先遍历(BFS)作为图的两种基本遍历方式,不仅具有深刻的理论意义,还广泛应用于各种实际问题中。本文将更深入地探讨这两种遍历方式的原理、实现细节、性能特点以及它们在实践中的应用。

深度优先遍历(DFS)的深入解析

1. 原理与实现

深度优先遍历的核心思想是从一个节点开始,沿着树的深度遍历树的节点,尽可能深地搜索树的分支。当节点v的所在边都已被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程可以通过递归或栈来实现。

  • 递归实现:利用函数调用栈来隐式地维护一个访问栈,每次递归调用都相当于将当前节点压入栈中,当递归返回时则相当于弹出栈顶节点。
  • 栈实现:显式地使用一个栈来模拟递归过程,手动控制节点的入栈和出栈。

2. 性能特点

  • 空间复杂度:递归实现的空间复杂度取决于递归深度,而栈实现的空间复杂度则与图中节点的最大深度成正比。在最坏情况下(如完全二叉树),空间复杂度为O(n),其中n为节点数。
  • 时间复杂度:遍历所有节点,时间复杂度为O(n+e),其中n为节点数,e为边数。在连通图中,由于每个节点和每条边都会被访问一次,所以时间复杂度可以简化为O(V+E),其中V和E分别为图的顶点集和边集。

3. 应用场景

  • 路径搜索:在图中搜索从起点到终点的所有可能路径。
  • 图的连通性检测:通过DFS可以判断一个图是否是连通的,或者将其划分为多个连通分量。
  • 拓扑排序:在有向无环图(DAG)中,利用DFS可以生成拓扑排序序列。
  • 解决迷宫问题:DFS是解决迷宫问题的一种有效方法,通过不断尝试和回溯来找到从起点到终点的路径。

JavaScript实现DFS(使用递归):

class Graph {  
    constructor() {  
        this.adjacencyList = {};  
    }  
  
    addEdge(u, v) {  
        if (!this.adjacencyList[u]) {  
            this.adjacencyList[u] = [];  
        }  
        this.adjacencyList[u].push(v);  
    }  
  
    DFS(start, visited = new Set()) {  
        if (!visited.has(start)) {  
            console.log(start);  
            visited.add(start);  
            if (this.adjacencyList[start]) {  
                this.adjacencyList[start].forEach(neighbor => {  
                    this.DFS(neighbor, visited);  
                });  
            }  
        }  
    }  
}  
  
// 使用示例  
const graph = new Graph();  
graph.addEdge('A', 'B');  
graph.addEdge('A', 'C');  
graph.addEdge('B', 'D');  
graph.addEdge('C', 'E');  
graph.addEdge('C', 'F');  
graph.addEdge('E', 'G');  
  
graph.DFS('A'); // 输出遍历顺序,可能因数据结构内部实现而异

广度优先遍历(BFS)的深入解析

1. 原理与实现

广度优先遍历的思想是从一个节点开始,先访问这个节点的所有邻接节点,然后再依次访问这些邻接节点的未被访问的邻接节点。这一过程通过队列来实现,队列中的元素按照被加入队列的顺序被访问。

2. 性能特点

  • 空间复杂度:主要取决于队列的大小,最坏情况下(如完全二叉树),空间复杂度为O(n),其中n为节点数。
  • 时间复杂度:同样为O(n+e),即遍历所有节点和边。

3. 应用场景

  • 最短路径问题:在无权图或所有边权重相同的图中,BFS可以用来求解单源最短路径问题(即求从源点到其他所有点的最短路径)。
  • 层次遍历:在树或图的层次结构中,BFS可以按层次顺序访问所有节点。
  • 搜索问题:在某些搜索问题中,如广度优先搜索(BFS)算法本身,就是基于BFS遍历来实现的。

JavaScript实现BFS

class Graph {  
    constructor() {  
        this.adjacencyList = {};  
    }  
  
    addEdge(u, v) {  
        if (!this.adjacencyList[u]) {  
            this.adjacencyList[u] = [];  
        }  
        this.adjacencyList[u].push(v);  
    }  
  
    BFS(start) {  
        const queue = [start];  
        const visited = new Set();  
  
        while (queue.length) {  
            const current = queue.shift();  
            if (!visited.has(current)) {  
                console.log(current);  
                visited.add(current);  
                if (this.adjacencyList[current]) {  
                    this.adjacencyList[current].forEach(neighbor => {  
                        if (!visited.has(neighbor)) {  
                            queue.push(neighbor);  
                        }  
                    });  
                }  
            }  
        }  
    }  
}  
  
// 使用示例  
const graph = new Graph();  
graph.addEdge('A', 'B');  
graph.addEdge('A', 'C');  
graph.addEdge('B', 'D');  
graph.addEdge('C', 'E');  
graph.addEdge('C', 'F');  
graph.addEdge('E', 'G');  
  
graph.BFS('A'); // 输出遍历顺序,通常按层次输出

DFS与BFS的比较

  • 空间复杂度:在大多数情况下,DFS和BFS的空间复杂度都是O(n),但在某些特殊情况下(如深度极大的图),DFS可能会因为递归深度过大而导致栈溢出,而BFS则相对更稳定。
  • 时间复杂度:两者都是O(n+e),但在实际应用中,由于DFS的回溯特性和BFS的层次特性,它们的表现可能会有所不同。
  • 应用场景:DFS更适合于深度优先搜索、路径查找、图的连通性检测等问题;而BFS则更适合于广度优先搜索、最短路径问题、层次遍历等问题。

结论

  • 深度优先遍历(DFS)  是一种递归遍历方法,通过递归或栈实现,尽可能深地遍历图的分支。
  • 广度优先遍历(BFS)  使用队列来实现,逐层遍历图中的所有节点。

深度优先遍历和广度优先遍历是图的两种基本遍历方式,它们各有优劣,适用于不同的应用场景。通过深入理解这两种遍历方式的原理、实现细节以及性能特点,我们可以更好地选择和应用它们来解决实际问题。同时,随着算法和数据结构领域的不断发展,DFS和BFS也将继续发挥重要作用,为更多高级算法和应用的实现提供有力支持。

标签:优先,遍历,graph,DFS,addEdge,BFS,广度,节点
From: https://blog.csdn.net/Jerry_zpon/article/details/142404644

相关文章

  • leetcode关于a++>等运算符优先级知识点辨析
    我偶然发现巧用++a>i可以大大缩减版面,方便检查。但对于相关优先级的知识点,我却有点模糊,所以对这个知识点进行辨析。1++a>i;a先加1,再与i比较2a++>i;a先与i比较再加13i<a++;a先比较再加14i<++a;a先加1再比较5--a>ia先减1再比较6a-->ia先比较再减17i<a--先......
  • 目录遍历
    是什么?目录遍历是网络配置缺陷,导致目录可以被任意浏览,使得一些隐私文件和目录被泄露。为什么?没有对../目录设置过滤、加密或权限,恶意用户可以跳转遍历服务器上的任意文件。防御方案加密参数传递的数据对参数进行base64加密后在进行传参编码绕过URL编码绕过文件后缀过滤......
  • 【C++二叉树】105.从前序与中序遍历序列构造二叉树
    105.从前序与中序遍历序列构造二叉树-力扣(LeetCode)根据前序遍历和中序遍历构建二叉树前序遍历访问方式:根-左子树-右子树中序遍历访问方式:左子树-根-右子树思路分析:前序+中序可以构建一颗二叉树:前序遍历可以确定根,中序遍历可以确定左子树的中序区间和右子树的中序区......
  • 20240919_214407 切片小结 树的遍历 随手笔记
    切片小结步长如果是正值那么找到下标的对应的成员左边切一刀最终向右包抄取值步长如果是负值找到下标对应的成员右边切一刀最终向左边包抄取值认识库SciPy:SciPy是一个开源的Python算法库和数学工具包,用于数学、科学、工程领域。它基于NumPy,提供了大量的数学算法和......
  • 【算法】堆与优先级队列
    【ps】本篇有4道 leetcode OJ。目录一、算法简介二、相关例题1)最后一块石头的重量.1-题目解析.2-代码编写2)数据流中的第K大元素.1-题目解析.2-代码编写3)前K个高频单词.1-题目解析.2-代码编写4)数据流的中位数.1-题目解析.2-代码编写 一、算......
  • Java-数据结构-优先级队列(堆)-(一) (;´д`)ゞ
    文本目录:❄️一、优先级队列:     ➷1、概念:❄️二、优先级队列的模拟实现:     ➷1、堆的概念:     ➷ 2、堆的性质:      ➷ 3、堆的创建: ▶向下调整:       ➷ 4、堆的插入和删除:    ▶堆的插入: ☞......
  • 【数据结构】二叉树的遍历
    堆的应用堆排列堆排序即利用堆的思想来进行排序,总共分为两个步骤:建堆升序:建大堆降序:建小堆利用堆删除思想来进行排序建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。voidHeapSort(int*a,intn){ //a数组直接建堆O(N) for(inti=......
  • 【DFS深度优先搜索】纵火犯
    【问题描述】给你一块n*m的草坪,问如果只点一次火,最多能烧多少块草坪。可以从n*m的草地中任意一个地方开始点火,火只能往上下左右传递,没有草的地方不能燃烧。【输入格式】输入由多个测试例组成。每个测试例的第一行含两个整数n和m,(1<=n,m<=100),分别表示01矩阵的行数与列......
  • 【自动化测试】常见的自动化遍历工具以及如何选择合适的自动化遍历工具
    引言自动化遍历测试通常依赖于特定的工具来实现应用的自动操作和测试文章目录引言一、常见的自动化遍历工具1.1Appium1.2Selenium1.3Calabash1.4RobotFramework1.5Espresso1.6XCTest1.7Macaca1.8TestComplete1.9UiAutomator1.10总结二、如何选择合适的自......
  • 搜索 DFS深度优先搜索
    洛谷P1363幻象迷宫这种恶魔样例究竟是哪个天才想出来的?!!!!!!620#.##.##.##.##.##.##.#.##.##.##.##.##.##.#.##.##.##.##.##.##.S.#..#..#..#..#..#..##..#..#..#..#..#..##..#..#..#..#..#..##md,交了好几发都没过,看了一下这个样例,心都凉了。能想出来这题解的更是天才Orz......