DFS与BFS算法

2023-11-01

深度优先遍历简称DFS(Depth First Search),广度优先遍历简称BFS(Breadth First Search),它们是遍历图当中所有顶点的两种方式。下面分别介绍两种基本的搜索算法。

理论介绍

深度优先遍历DFS

DFS属于图算法的一种,是针对图和树的遍历算法。深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。一般用堆或栈来辅助实现DFS算法。其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,如果遇到死路就往回退,回退过程中如果遇到没探索过的支路,就进入该支路继续深入,每个节点只能访问一次。

广度优先遍历BFS

广度优先搜索(也称宽度优先搜索)是连通图的一种遍历算法,也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和广度优先搜索类似的思想。属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。基本过程,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。一般用队列数据结构来辅助实现BFS算法。

广度优先搜索应用:层序遍历、最短路径、求二叉树的最大高度、
由点到面遍历图、拓扑排序

深度优先搜索应用:先序遍历,中序遍历,后序遍历

图解

假设从0开始访问所有节点,可能的路径有哪些?
在这里插入图片描述(1)DFS方法
首先选择1,然后到7、8,发现走不动了。
在这里插入图片描述
然后退回到7,再探索节点10。回退到1,探索9:在这里插入图片描述
再退回到景点0,后续依次探索2、3、5、4、6,走完所有节点:在这里插入图片描述
二叉树的前序、中序、后序遍历,本质上可以认为是深度优先遍历。是一种回溯思想。
(2)BFS方法
首先探索节点0的相邻节点1、2、3、4:
在这里插入图片描述接着,探索与节点0相隔一层的7、9、5、6:
在这里插入图片描述最后,探索与节点0相隔两层的节点8、10:
在这里插入图片描述
可以看出,BFS是一层一层的由内向外遍历,二叉树的层序遍历本质上可以认为是广度优先遍历。

代码框架

DFS

非递归:
1.利用栈实现
2.从源节点开始把节点按照深度放入栈,然后弹出
3.每弹出一个点,把该节点下一个没有进过栈的邻接点放入栈
4.直到栈为空

BFS

1.利用队列实现
2.从源节点开始依次按照宽度进队列,然后弹出
3.每弹出一个节点,就把该节点所有没有进过队列的邻接点放入队列
4.直到队列为空

供参考:

class Graph:
    # *args 把参数打包成tuple供函数调用。**kwargs把 x = a,y=b打包成字典{x:a,y:b}供函数调用
    def __init__(self, *args, **kwargs):
        self.neighbors = {}
        self.visited = {}
        
    def add_nodes(self, nodes):
        for node in nodes: 
            self.add_node(node)
    
    def add_node(self, node):
        print('self.nodes()',self.nodes())
        if node not in self.nodes():
            self.neighbors[node] = [node]

    def add_edge(self, edge):
        u, v = edge
        if u not in self.neighbors[v] and v not in self.neighbors[u]:
            self.neighbors[u].append(v)
            if u != v:  # 没有自环
                self.neighbors[v].append(u)
    
    def nodes(self):
        return self.neighbors.keys()
   
    # 递归 DFS
    def depth_first_search(self, root = None):
        order = []
      
        def dfs(node):
            self.visited[node] = True
            order.append(node)
            for n in self.neighbors[node]:
                if n not in self.visited:
                    dfs(n) 
        if root:
            dfs(root)  # dfs(0)
        # print('visited', self.visited) 
         #对于不连通的结点(即dfs(root)完仍是没有visit过的单独处理,再做一次dfs
        for node in self.nodes():
            if node not in self.visited:
                dfs(node)
        self.visited = {}
        print(order)
        # print('final visited', self.visited)
        return order
    
    # 非递归 DFS
    def depth_first_search_2(self, root=None):
        stack = []
        order = []
        def dfs():
            while stack:
                print('stack',stack)
                node = stack[-1] # 栈顶元素
                for n in self.neighbors[node]:
                    if n not in self.visited:
                        order.append(n)
                        stack.append(n)
                        # stack.append(self.neighbors[n])
                        self.visited[n] = True
                        print('self.visited', self.visited)
                        break
                else: 
                    stack.pop() 
                
        if root:
            stack.append(root)
            order.append(root)
            self.visited[root] = True
            dfs()    
        for node in self.nodes():
            if node not in self.visited:
                stack.append(node)
                order.append(node)
                self.visited[node] = True    
                dfs()       
        # self.visited = {}  # 非必须
        print(order)
        return order
    
    # BFS
    def breadth_first_search(self,root=None):
        que = []
        order = []
        def bfs():
            while len(que) > 0: # 队列非空
                node = que.pop(0) # 从左侧开始弹出  list对象有pop但是没有popleft
                self.visited[node] = True
                for n in self.neighbors[node]:
                    print('self.visited', self.visited)
                    print('que', que)
                    if n not in self.visited and n not in que:
                        que.append(n)
                        order.append(n)
        if root:
            que.append(root)
            order.append(root)
            bfs()
            
        for node in self.nodes():
            if not node in self.visited:
                que.append(node)
                order.append(node)
                
        self.visited = {}
        print(order)
        return order        

参考:
https://blog.csdn.net/weixin_40314737/article/details/80893507

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

DFS与BFS算法 的相关文章

随机推荐

  • 4.15总结

    熟悉并完成白盒题目 十分重要 写白盒一定按照格式要求有头部部分就马上写一个尾部部分出来 下列流程图中变量a b c d均为非负整数 编写程序实现相应分析处理 并设计测试数据进行语句覆盖测试 要求a b c d取最小可能值 import ja
  • 把keilC51中不使用的代码禁止分配空间,为程序瘦身!

    把target options中的device页中选上 Use LX51 然后在LX51 Misc页中的Misc Control中填入 REMOVEUNUSED 确认后重新编译即可自动去掉未调用的函数 如下图
  • Zookeeper原理架构

    本文纯属个人笔记 通俗易懂 转载请附上原文链接 部分资料摘自网络 如有雷同 纯属巧合 更多资料见个人博客 https www rabbitai cn Zookeeper到底是什么 学一个东西 不搞明白他是什么东西 哪还有心情学啊 首先 Zo
  • Python 用几何布朗运动模型和蒙特卡罗Monte Carlo随机过程模拟股票价格可视化分析耐克NKE股价时间序列数据

    最近我们被客户要求撰写关于蒙特卡罗的研究报告 包括一些图形和统计输出 介绍 金融资产 证券已使用多种技术进行建模 该项目的主要目标是使用几何布朗运动模型和蒙特卡罗模拟来模拟股票价格 该模型基于受乘性噪声影响的随机 与确定性相反 变量 相关视
  • js给页面添加随机像素噪声背景

    WIDTH和HEIGHT可以取小一点 但是取太小很不好看 因为生成的噪声看起来不随机了 小片区域就有重复 创建一个canvas但不放页面 这个canvas只用来生成图片 然后循环遍历在canvas里面画1px的矩形 toDataURL自动就
  • c++拷贝构造函数可以访问私有成员

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 在学习拷贝构造函数的时候 突然发现拷贝构造函数里面可以访问私有成员 当时很疑惑 和c 类的private私有属性不同 但是编译器可以编译通过 class MyString
  • Spring Bean的生命周期和作用域

    首先我们来介绍Spring Bean的作用域 默认Spring IOC初始化Bean是单例的 及在beanFactory中Bean都是单例 调用getBean的时候 返回的都是同一个Bean对象 SpringBean的五大作用域如下 sin
  • CentOS 7系统安装时不能进入图形化安装界面

    在安装界面 1 光标选中 install centos 7 2 按键盘 TAB 键 3 在内容的最后一行末尾添加上 nodomeset 原因 centos7安装包里自带的显卡驱动不兼容主机上的显卡 nodomeset表示不加载centos7
  • 使用Java的RandomAccessFile类实现大文件分片上传功能

    使用Java的RandomAccessFile类实现大文件分片上传功能 在开发过程中 我们经常会面对需要上传和处理大文件的场景 为了提高效率和降低内存消耗 一种常见的解决方案是将大文件切分成多个小片段进行上传 在本文中 我将详细介绍如何使用
  • Vue创建高德地图,监听地图层级的变化进行操作

    createmap let that this 创建地图 MapLoader then AMap gt that map new AMap Map containerRight zoom that defaultZoom center th
  • Android 蓝牙 hfp音频连接

    Android 蓝牙 hfp音频连接 1 连接音频 2 音频连接状态 该文章基于Android Q 1 连接音频 在手机音频正常连接时 接通电话 点选蓝牙通话 mDeviceManager connectAudio返回true 如果是之前默
  • 【已解决】使用tensorflow报错:ModuleNotFoundError:No module named ‘tensorflow.contrib‘

    问题描述 运行基于tensorflow的代码 原代码在tensorflow v1的基础上编写 当前tensorflow大多是v2 因此运行时会出现下列错误 原有方案 按照博客 需做如下修改 将import tensorflow as tf
  • unity 判断文件夹下是否有指定文件_详解如何提取Unity素材,源码

    一 判断是否是Unity打包及打包方式 如果lib文件夹下有libunity so就证明这是一个unity3d游戏 目前Unity有两种打包方式 Mono和IL2CPP 两者解压后的文件内容也是不相同的 如果MONO里面有很多DLL文件说明
  • kafka sasl_ssl配置

    一 切换到存储证书的路径 我这里在家目录中的创建了ssl文件夹 mkdir ssl cd ssl 二 生成服务端密钥库 keytool keystore server keystore jks alias localhost validit
  • 神经网络与TensorFlow相关知识

    目录 一 全连接的BP神经网络 1 BP back propagation反传播 神经网络 2 全连接神经网络 2 1 全连接神经网络的原理 2 1 1内部运算逻辑 2 1 2 反向传播 2 1 3 为了让Loss最小 求解出最佳的w和b
  • input 标签 (详解)如何去除输入时边框

    去掉input边框
  • Pycharm 翻译插件失效(transaction) 问题解决【含视频教程】

    前言 嗨嗨 大家好 最近有很多朋友反应 翻译插件用不了了 那么今天教大家如何快速解决这个问题 不想看文章的朋友 可以直接点击文章最下方QQ群 领取视频版教程 嘘 偷偷借用我们巳月老师的文章 给你们分享分享吧 嘿嘿 1 点击文件 file g
  • 酷开系统AI智能让生活更简单化

    在一个痴迷于速度和便利性的世界中 AI语音识别创造了一个时代 您可以简单地与您的计算机 智能手机或家庭集线器通信 并获得您正在寻找的答案 而无需在键盘上键入任何内容 现在酷开系统 也开启了AI识别的时代 酷开系统 通过画质识别千万用户画像
  • 【Three.js】第一、二章 入门指南和基础知识

    01 介绍 Three js 非常庞大 你可以用它做无数的事情 在第一章中 我们将学习所有基础知识 例如创建第一个场景 渲染 添加对象 选择正确的材料 添加纹理 为所有内容制作动画 甚至将其放到网上 有些人可能会觉得这部分有点无聊 因为课程
  • DFS与BFS算法

    深度优先遍历简称DFS Depth First Search 广度优先遍历简称BFS Breadth First Search 它们是遍历图当中所有顶点的两种方式 下面分别介绍两种基本的搜索算法 理论介绍 深度优先遍历DFS DFS属于图算