PYTHON实现图的深度优先搜索(DFS)和广度优先搜索(BFS)算法

使用邻接表来表示图的结构,Python 代码演示邻接表的深度优先遍历和广度优先遍历的实现。


# 深度优先搜索(Depth-First Search, DFS)算法函数
# 使用集合来记录已经访问过的节点,在遍历过程中递归访问每个节点的邻居节点,并打印访问顺序。
def dfs(graph, start, visited=None):
    # 若visited参数未提供,则初始化为None
    if visited is None:
        # 使用集合存储已访问的节点,确保每个节点只被访问一次
        visited = set()
    
    # 将当前起始节点添加到已访问节点集合中
    visited.add(start)
    
    # 打印当前节点,表示访问了该节点
    print(start)
    
    # 遍历当前节点的邻居节点
    for neighbor in graph[start] - visited:
        # 对未访问过的邻居节点进行递归调用DFS函数
        dfs(graph, neighbor, visited)
    
    # 返回最终访问过的所有节点集合
    return visited

# 定义图的邻接表结构
graph = {
    'A': {'B', 'C'},
    'B': {'A', 'D', 'E'},
    'C': {'A', 'F'},
    'D': {'B'},
    'E': {'B', 'F'},
    'F': {'C', 'E'}
}

# 从'A'节点开始执行深度优先搜索
dfs(graph, 'A')


print('----------------------------------')


# 广度优先搜索(Breadth-First Search, BFS)算法函数
# 利用双端队列和集合数据结构实现了广度优先搜索的原理,按照逐层扩展探索的方式遍历整个图并输出访问顺序。
from collections import deque

def bfs(graph, start):
    # 使用集合存储已访问的节点,确保每个节点只被访问一次
    visited = set()
    
    # 使用双端队列(deque)来实现BFS的队列结构,从起始点开始探索
    queue = deque([start])
    
    # 将起始节点标记为已访问
    visited.add(start)
    
    # 当队列不为空时循环执行BFS
    while queue:
        # 从队列左侧取出顶点作为当前节点
        vertex = queue.popleft()
        
        # 打印当前节点,表示访问了该节点
        print(vertex)
        
        # 遍历当前节点的邻居节点
        for neighbor in graph[vertex] - visited:
            # 将未访问过的邻居节点加入已访问集合和队列中
            visited.add(neighbor)
            queue.append(neighbor)

# 定义图的邻接表结构
graph = {
    'A': {'B', 'C'},
    'B': {'A', 'D', 'E'},
    'C': {'A', 'F'},
    'D': {'B'},
    'E': {'B', 'F'},
    'F': {'C', 'E'}
}

# 从'A'节点开始执行广度优先搜索
bfs(graph, 'A')

简要解释一下这两种遍历算法的原理和代码实现。

深度优先遍历算法原理:

深度优先遍历 (Depth First Search, DFS) 是一种用于遍历或搜索树或图的算法。在这种遍历过程中,从起始顶点开始,沿着路径一直走到最深处,直到不能再前进为止,然后返回上一级,继续探索未被访问的分支。这一过程是递归的。深度优先遍历在图中一般使用栈来实现。

深度优先遍历算法实现:

  1. 创建一个布尔数组 visited[],用于记录顶点是否已被访问过。
  2. 从给定的起始顶点开始,递归地遍历该顶点的所有未访问过的邻接顶点。
  3. 在访问每个顶点时,将其标记为已访问,并递归地遍历其邻接顶点。
  4. 重复以上步骤,直到所有可达的顶点都被访问过。

广度优先遍历算法原理:

广度优先遍历 (Breadth First Search, BFS) 也是一种用于遍历或搜索树或图的算法。在这种遍历过程中,从起始顶点开始,依次访问该顶点的所有邻接顶点,然后再依次访问这些邻接顶点的邻接顶点,以此类推,直到图中所有可达顶点都被访问。广度优先遍历一般使用队列来实现。

广度优先遍历算法实现:

  1. 创建一个布尔数组 visited[],用于记录顶点是否已被访问过。
  2. 创建一个空队列 queue,用于存储待访问的顶点。
  3. 将起始顶点加入队列,并标记为已访问。
  4. 从队列中取出一个顶点,访问其所有未被访问过的邻接顶点,并将这些邻接顶点加入队列中。
  5. 重复以上步骤,直到队列为空。

这两种遍历算法都具有其独特的应用场景和优劣势,选择哪种算法取决于具体问题的要求和性质。

-------------------

这段代码定义了一个图(Graph)类,实现了图的深度优先搜索(DFS)和广度优先搜索(BFS)算法。使用邻接表来表示图的结构。下面是对代码中各个部分的详细注释:

  • __init__(self): 类的初始化方法,初始化一个空的邻接表图。

  • add_edge(self, u, v): 添加边的方法,将顶点u和v之间的边加入图中。

  • dfs_util(self, v, visited): 深度优先搜索的辅助方法,以顶点v为起点进行深度优先搜索,并标记已访问过的顶点。

  • dfs(self, v): 深度优先搜索方法,以顶点v为起点进行深度优先搜索。

  • bfs(self, v): 广度优先搜索方法,以顶点v为起点进行广度优先搜索。

在下面的代码部分,首先创建了两个图实例,分别进行了深度优先搜索和广度优先搜索,并输出了搜索结果。

from collections import defaultdict

class Graph:
    def __init__(self):
        # 使用 defaultdict(list) 创建了一个默认值为列表的字典,用于存储图的邻接表
        self.graph = defaultdict(list)

    def add_edge(self, u, v):
        """
        添加边的方法
        :param u: 边的起始顶点
        :param v: 边的终止顶点
        """
        self.graph[u].append(v)  # 将终止顶点添加到起始顶点的邻接列表中

    def dfs_util(self, v, visited):
        """
        深度优先搜索的辅助函数
        :param v: 当前顶点
        :param visited: 用于标记顶点是否已被访问的列表
        """
        visited[v] = True  # 将当前顶点标记为已访问
        print(v, end=' ')  # 打印当前顶点

        for i in self.graph[v]:
            if not visited[i]:
                self.dfs_util(i, visited)  # 递归调用深度优先搜索函数访问当前顶点的未访问邻接顶点

    def dfs(self, v):
        """
        深度优先搜索方法
        :param v: 搜索起始顶点
        """
        visited = [False] * (max(self.graph) + 1)  # 创建标记列表,初始时所有顶点均未被访问
        self.dfs_util(v, visited)  # 调用深度优先搜索辅助函数

    def bfs(self, v):
        """
        广度优先搜索方法
        :param v: 搜索起始顶点
        """
        visited = [False] * (max(self.graph) + 1)  # 创建标记列表,初始时所有顶点均未被访问
        queue = []  # 创建空队列,用于存储待访问顶点
        queue.append(v)  # 将起始顶点加入队列
        visited[v] = True  # 将起始顶点标记为已访问

        while queue:
            v = queue.pop(0)  # 取出队列中的第一个顶点
            print(v, end=' ')  # 打印当前访问的顶点

            for i in self.graph[v]:
                if not visited[i]:
                    queue.append(i)  # 将未访问过的邻接顶点加入队列
                    visited[i] = True  # 标记邻接顶点为已访问

# 邻接表的深度遍历
print("邻接表的深度遍历:")
g_dfs = Graph()
g_dfs.add_edge(0, 1)
g_dfs.add_edge(0, 2)
g_dfs.add_edge(1, 2)
g_dfs.add_edge(2, 0)
g_dfs.add_edge(2, 3)
g_dfs.add_edge(3, 3)

g_dfs.dfs(2)  # 从顶点2开始深度优先遍历

print("\n")

# 邻接表的广度遍历
print("邻接表的广度遍历:")
g_bfs = Graph()
g_bfs.add_edge(0, 1)
g_bfs.add_edge(0, 2)
g_bfs.add_edge(1, 2)
g_bfs.add_edge(2, 0)
g_bfs.add_edge(2, 3)
g_bfs.add_edge(3, 3)

g_bfs.bfs(2)  # 从顶点2开始广度优先遍历

解释一下def bfs(self, v):的功能:

  1. bfs(self, v): 这是一个类方法,用于执行广度优先搜索。它接受一个参数 v,表示搜索的起始顶点。

  2. visited = [False] * (max(self.graph) + 1): 创建一个布尔类型的列表 visited,用于标记顶点是否已被访问过。列表的长度为图中顶点编号的最大值加一,初始化所有元素为 False

  3. queue = []: 创建一个空队列,用于存储待访问的顶点。

  4. queue.append(v): 将起始顶点 v 加入队列,并将其标记为已访问。

  5. while queue:: 当队列不为空时,执行循环,表示还有顶点需要被访问。

  6. v = queue.pop(0): 从队列中取出一个顶点 v,并将其从队列中移除。这里使用 pop(0) 表示从队列的头部取出元素,即先进先出。

  7. print(v, end=' '): 打印当前访问的顶点 v

  8. for i in self.graph[v]:: 遍历当前顶点 v 的所有邻接顶点。

  9. if not visited[i]:: 如果邻接顶点 i 还未被访问过,则将其加入队列,并标记为已访问。

这样,通过不断将邻接顶点加入队列,直到队列为空,就完成了广度优先搜索算法的执行过程。在执行过程中,顶点的访问顺序按照它们距离起始顶点的距离逐层增加,因此可以实现广度优先的搜索策略。

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

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

相关文章

长难句打卡5.9

For example, the Long Now Foundation has as its flagship project a mechanical clock that is designed to still be marking time thousands of years hence. 例如,今日永存资金会将机械钟表视为旗舰项目,因此该钟表旨在为未来几千年保持计时。 Foundation n.基金会flag…

数据库(MySQL)—— 索引

数据库(MySQL)—— 索引 什么是索引创建索引使用 CREATE INDEX 语句使用 ALTER TABLE 语句在创建表时定义索引特殊类型索引注意事项 举个例子无索引的情况有索引的情况为什么索引快索引的结构 今天我们来看看MySQL中的索引: 什么是索引 MyS…

unity基础(一)

内容概要: 生命周期函数vector3 位置 方向 缩放旋转等信息Vector3欧拉角和Quaternion四元素unity脚本执行顺序设置 一 生命周期函数 方法说明Awake最早调用,所以一般可以再此实现单例模式OnEnable组件激活后调用,在Awake后会调用一次Start在Update之前调用一次&a…

硬件知识积累 音频插座的了解,看音频插座的原理图来了解音频插座的引脚。

1. 音频接口 音频插座是一种用于连接音频信号线路的电子元件,常见于音频设备(如音响、耳机、话筒等)中。它的主要作用是将电子信号转化为声音信号,以满足人们对于音乐、电影、游戏等方面的需求。 根据插头形状的不同,音…

和comate一起,用JavaScript实现一个简易版五子棋小游戏

前言 五子棋起源于中国,是全国智力运动会竞技项目之一,是一种两人对弈的纯策略型棋类游戏。双方分别使用黑白两色的棋子,下在棋盘直线与横线的交叉点上,先形成五子连珠者获胜。 这次和Baidu Comate智能代码助手共同完成这个小游戏…

[华为OD] C卷 田忌赛马 DFS 200

题目: 给定两个只包含数字的数组a, b,调整数组a里面数字的顺序,使得尽可能多的a[i] >b[i]。 数组a和b中的数字各不相同。 输出所有可以达到最优结果的a数组的数量 输入描述 输入的第一行是数组a中的数字,其中只包含数字,每…

LVS DR模式部署

一、LVS 简介 LVS的三种工作模式 NAT 地址转换 调度器会作为所有节点服务器的默认网关,也是客户端的访问入口和节点服务器返回响应消息的出口,所以调度器会承载双向流量的负载压力,可能会为整个群集的性能瓶颈。由于节点服务器都会处于内网…

AcWing 4993 FEB

4993. FEB - AcWing题库 大佬亲笔 将原串分成三段&#xff1a; FFF|E.....B|FFF 先合并中间段&#xff0c;再合并两边的段 #include <iostream> #include <cstring> #include <algorithm> #include <string> #include <queue&g…

Eclipse下载安装教程(包含JDK安装)【保姆级教学】【2023.10月最新版】

目录 文章最后附下载链接 第一步&#xff1a;下载Eclipse&#xff0c;并安装 第二步&#xff1a;下载JDK&#xff0c;并安装 第三步&#xff1a;Java运行环境配置 安装Eclipse必须同时安装JDK &#xff01;&#xff01;&#xff01; 文章最后附下载链接 第一步&#xf…

ES:聚合查询语法

基础查询结构&#xff1a; GET http://ip:prot/textbook/_search { "query" : { ...query子句... }, "aggs" : { "agg_name":{ "agg_type": { "agg_arg": agg_arg_value } } }, "sort" : { ..sor…

快速学习Python:新手入门指南

一、确定学习目标 首先&#xff0c;你需要明确自己学习Python的目标。是希望成为一名Python开发人员&#xff0c;还是仅仅想在数据分析、数据可视化等领域使用Python。不同的目标需要不同的学习路径和资源。 二、选择合适的教材和课程 Python的学习资源非常丰富&#xff0c;…

vscode 使用正则搜索

ctrl c 复制&#xff0c;内容如下&#xff1a; Vue3简介创建Vue3工程Vue3核心语法路由pinia组件通信其它 APIVue3新组件

HDLbits 刷题 -- Exams/m2014 q3

Consider the function f shown in the Karnaugh map below. Implement this function. d is dont-care, which means you may choose to output whatever value is convenient. 译&#xff1a;考虑下面卡诺图中显示的函数f。 实现这个函数。D是dont-care&#xff0c;这意味着…

别再观望!2024年必做的项目:视频号无货源

大家好&#xff0c;我是电商花花。 现在做项目&#xff0c;更喜欢的是一个能稳定出单&#xff0c;稳定发展的一个创业项目&#xff0c;一个好的项目就是能长期稳定的发展&#xff0c;如果只追求短平快收益的项目&#xff0c;这样的项目也并不适合我们。 对于越来越火爆的视频…

MoviePy(Python音视频开发)

音视频基础帧率、码率、分辨率视频格式H.264和H.265视频压缩算法 Moviepy常见剪辑类VideoFlieClipImageFlieClipColorClipTextClipCompositeVideoClipAudioFlieClipCompositeAudioClip 常见操作音视频的读入与导出截取音视频 音视频基础 帧率、码率、分辨率 体积&#xff08;V…

TL-WN826N无线网卡连接电脑蓝屏,提示rtl8188gu.sys

TL-WN826N无线网卡插电脑就蓝屏&#xff0c;提示rtl8188gu.sys 处理方法&#xff1a; 设备管理器中卸载其他的2.0无线网卡程序和功能中卸载网卡驱动TPlink官网下载 TL-WN826N V1.0_1.0.0&#xff08;https://www.tp-link.com.cn/product_572.html?vdownload&#xff09;&…

Redis简介和数据结构

目录 简介 进入之后身份认证才能使用 优点 用途&#xff1a; 数据结构 string string自动扩容 Redis中的简单动态字符串&#xff08;SDS&#xff09;具有以下优点&#xff1a; SDS数据的编码格式 比较&#xff1a; string 常用操作 分布式锁 使用情况&#xff0c;…

每日Attention学习2——Multi-Scale Convolutional Attention

模块出处 [link] [code] [NIPS 22] SegNeXt: Rethinking Convolutional Attention Design for Semantic Segmentation 模块名称 Multi-Scale Convolutional Attention (MSCA) 模块作用 多尺度特征提取&#xff0c;更大感受野 模块结构 模块代码 import torch import torch.…

【启明智显技术分享】“ESP-IDF环境搭建全攻略:告别基于乐鑫方案彩屏开发中的搭建难题”

前言&#xff1a; 【启明智显】专注于HMI&#xff08;人机交互&#xff09;及AIoT&#xff08;人工智能物联网&#xff09;产品和解决方案的提供商&#xff0c;我们深知彩屏显示方案在现代物联网应用中的重要性。为此&#xff0c;我们一直致力于为客户提供彩屏显示方案相关的技…

深度解析:数据结构二叉树(1)

✅作者简介&#xff1a;大家好&#xff0c;我是再无B&#xff5e;U&#xff5e;G&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a; 再无B&#xff5e;U&#xff5e;G-CSDN博客 目标 1. 掌握树的基本概念 2. 掌握二叉…
最新文章