Python实战开发及案例分析(22)—— 深度优先

        深度优先搜索(Depth-First Search, DFS)是一种用于遍历或搜索树或图的算法。与广度优先搜索不同,深度优先搜索尽可能深地遍历图的分支,直到找到目标或达到死胡同后才回溯。DFS可以使用递归实现或利用栈来进行非递归实现。

Python中的DFS实现

        以下是使用Python实现深度优先搜索的两种方式:递归和非递归(使用栈)。

图的定义

        首先,定义一个图,这里使用字典来实现,其中键是节点,值是与该节点直接相连的节点列表。

graph = {'A': ['B', 'C'],'B': ['D', 'E'],'C': ['F'],'D': [],'E': ['G'],'F': [],'G': []
}
递归实现DFS

        递归是实现DFS的一种直观方式。

def dfs_recursive(graph, vertex, visited=None):if visited is None:visited = set()visited.add(vertex)print(vertex, end=' ')  # 处理节点,这里是打印节点for neighbor in graph[vertex]:if neighbor not in visited:dfs_recursive(graph, neighbor, visited)# 调用DFS函数
dfs_recursive(graph, 'A')
非递归实现DFS

        非递归实现使用栈来模拟递归过程。

def dfs_iterative(graph, start):visited = set()stack = [start]while stack:vertex = stack.pop()if vertex not in visited:print(vertex, end=' ')visited.add(vertex)# 将邻接节点逆序压栈,以保持与递归版本相同的遍历顺序stack.extend(reversed(graph[vertex]))# 调用DFS函数
dfs_iterative(graph, 'A')

案例分析:迷宫寻路问题

        假设有一个迷宫,表示为一个二维网格,其中1代表墙壁,0代表可通行区域。我们需要找到从起点到终点的路径。

迷宫定义
maze = [[0, 1, 0, 0, 0],[0, 1, 0, 1, 0],[0, 0, 0, 0, 0],[0, 1, 1, 0, 0],[0, 0, 0, 0, 0]
]
DFS求解迷宫

        使用DFS找到从左上角到右下角的一条路径。

def dfs_maze(maze, start, goal):directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]  # 可移动方向(右,下,左,上)stack = [(start, [start])]visited = set([start])while stack:(x, y), path = stack.pop()if (x, y) == goal:return pathfor dx, dy in directions:nx, ny = x + dx, y + dyif 0 <= nx < len(maze) and 0 <= ny < len(maze[0]) and maze[nx][ny] == 0 and (nx, ny) not in visited:visited.add((nx, ny))stack.append(((nx, ny), path + [(nx, ny)]))return None# 起点和终点
start_pos = (0, 0)
end_pos = (4, 4)
path = dfs_maze(maze, start_pos, end_pos)
print("Path from start to goal:", path)

总结

        深度优先搜索是一种强大的搜索算法,适用于路径寻找、解决方案空间探索等多种场景。通过递归或非递归的栈实现,DFS可以有效地探索所有可能的路径直到找到解决方案或遍历所有节点。其应用不仅限于理论问题,还广泛适用于实际的编程和工程任务中。

        继续深入探讨深度优先搜索(DFS)的进阶应用,我们可以考虑其在解决图中的连通性问题、拓扑排序、寻找强连通分量等方面的实用性。这些应用突出了DFS在更复杂图结构问题中的效率和实用性。

图中的连通性问题

        DFS非常适用于检查或发现图中的所有连通分量。连通分量是一个无向图中最大的连通子图,其中任意两个顶点都有路径相连。

示例:发现所有连通分量
def dfs_connected_components(graph, start, visited):stack = [start]while stack:vertex = stack.pop()if vertex not in visited:visited.add(vertex)stack.extend(graph[vertex] - visited)return visiteddef find_connected_components(graph):visited = set()components = []for vertex in graph:if vertex not in visited:component = dfs_connected_components(graph, vertex, visited.copy())components.append(component)return components# 定义一个图
graph = {'A': set(['B', 'C']),'B': set(['A', 'D']),'C': set(['A']),'D': set(['B']),'E': set(['F']),'F': set(['E']),
}components = find_connected_components(graph)
print("Connected components:", components)

        在这个例子中,find_connected_components 函数利用 DFS 探索图中的每个顶点,并标记已访问的顶点,以发现并返回所有独立的连通分量。

拓扑排序

        拓扑排序是有向无环图(DAG)的线性排序,其中每个节点出现在其所有直接后继之前。DFS可以有效实现拓扑排序。

示例:使用DFS实现拓扑排序
def dfs_topological_sort(graph, start, visited, stack):visited.add(start)for neighbor in graph[start]:if neighbor not in visited:dfs_topological_sort(graph, neighbor, visited, stack)stack.append(start)def topological_sort(graph):visited = set()stack = []for vertex in graph:if vertex not in visited:dfs_topological_sort(graph, vertex, visited, stack)return stack[::-1]  # 返回反转的栈# 定义一个DAG
dag = {'A': ['C'],'B': ['C', 'D'],'C': ['E'],'D': ['F'],'E': [],'F': []
}order = topological_sort(dag)
print("Topological Order:", order)

        在这个例子中,topological_sort 利用DFS遍历图,保证所有节点的后继节点都已经被放置到栈中,从而实现拓扑排序。

寻找强连通分量

        强连通分量是有向图中的最大子图,其中任意两个顶点都互相可达。利用DFS可以有效地找到图中的所有强连通分量。

示例:使用Kosaraju算法找到强连通分量
def dfs_for_scc(graph, vertex, visited, stack):visited.add(vertex)for neighbor in graph[vertex]:if neighbor not in visited:dfs_for_scc(graph, neighbor, visited, stack)stack.append(vertex)def transpose_graph(graph):transposed = {v: [] for v in graph}for vertex in graph:for neighbor in graph[vertex]:transposed[neighbor].append(vertex)return transposeddef find_scc(graph):stack = []visited = set()# Fill vertices in stack according to their finishing timesfor vertex in graph:if vertex not in visited:dfs_for_scc(graph, vertex, visited, stack)# Transpose the graphtransposed = transpose_graph(graph)# The final DFS according to the order defined by the stackvisited.clear()scc = []while stack:vertex = stack.pop()if vertex not in visited:component_stack = []dfs_for_scc(transposed, vertex, visited, component_stack)scc.append(component_stack)return scc# 定义有向图
directed_graph = {'A': ['B'],'B': ['C'],'C': ['A', 'D'],'D': ['E'],'E': ['F'],'F': ['D', 'G'],'G': []
}scc = find_scc(directed_graph)
print("Strongly connected components:", scc)

        在这个示例中,使用Kosaraju算法的两次DFS遍历来找出所有的强连通分组。第一次DFS决定节点处理的顺序,第二次DFS在图的转置上执行,发现强连通分量。

总结

        DFS的这些高级应用展示了它在解决复杂图结构问题方面的强大功能,无论是分析网络的结构特性、排序问题还是分组问题,DFS都能提供高效的解决方案。通过适当的实现和优化,DFS可以帮助解决现实世界中的许多关键技术挑战。

        深入探讨深度优先搜索(DFS)在更多领域中的高级应用,可以发现这种算法不仅适用于图和树的基本遍历,还可以被扩展应用于解决更多复杂的问题,如解决组合问题、搜索算法优化、以及多维数据结构的探索等。以下是DFS在这些领域中的一些具体应用案例。

组合问题

        在解决组合问题时,如求解子集、排列、组合等,DFS提供了一种系统地遍历所有可能选择的方法。

示例:求解所有子集

        给定一个不含重复元素的整数数组,求所有可能的子集(幂集)。

def subsets(nums):result = []def dfs(index, path):result.append(path)for i in range(index, len(nums)):dfs(i + 1, path + [nums[i]])dfs(0, [])return resultnums = [1, 2, 3]
print("Subsets:", subsets(nums))

        这个示例中,通过递归地探索每个元素包含或不包含的所有可能,系统地生成了数组的所有子集。

搜索算法优化

        在某些搜索问题中,通过DFS结合剪枝策略,可以有效地减少搜索空间,优化算法性能。

示例:解数独

        使用DFS来填充数独,同时在每步通过剪枝减少不必要的搜索。

def solveSudoku(board):def is_valid(x, y, n):for i in range(9):if board[i][y] == n or board[x][i] == n:return Falseif board[3 * (x // 3) + i // 3][3 * (y // 3) + i % 3] == n:return Falsereturn Truedef dfs():for i in range(9):for j in range(9):if board[i][j] == '.':for num in '123456789':if is_valid(i, j, num):board[i][j] = numif dfs():return Trueboard[i][j] = '.'return Falsereturn Truedfs()# 假设board已被初始化为一个具体的数独问题
# solveSudoku(board)
# print("Solved Sudoku Board:", board)

        在这个示例中,DFS递归地尝试每个空格的所有可能数字,并通过有效性检查剪枝。

多维数据结构的探索

        DFS也可以应用于探索多维数据结构,比如在多维数组或矩阵中寻找特定模式或路径。

示例:岛屿数量计算

        给定一个由 '1'(陆地)和 '0'(水)组成的二维网格,计算网格中的岛屿数量。

def numIslands(grid):def dfs(x, y):if not (0 <= x < len(grid) and 0 <= y < len(grid[0]) and grid[x][y] == '1'):returngrid[x][y] = '0'for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:dfs(x + dx, y + dy)count = 0for i in range(len(grid)):for j in range(len(grid[0])):if grid[i][j] == '1':dfs(i, j)count += 1return count# grid = [...]
# print("Number of islands:", numIslands(grid))

        这个示例中,通过DFS遍历每块陆地,并将与之相连的所有陆地标记为访问过,从而计算出岛屿的总数。

总结

        通过以上案例,我们可以看到DFS不仅在理论中应用广泛,其在实际问题解决中的灵活性和强大功能也得到了充分展示。无论是组合问题的求解、复杂搜索任务的优化,还是复杂数据结构的深入探索,DFS都能提供有效的解决方案。这些高级应用表明,深度优先搜索是解决计算机科学问题中不可或缺的工具之一。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

量子计算机接入欧洲最快超算!芬兰加快混合架构算法开发

内容来源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 文丨浪味仙 排版丨沛贤 深度好文&#xff1a;1900字丨7分钟阅读 摘要&#xff1a;芬兰技术研究中心&#xff08;VTT&#xff09;与 CSC 展开合作&#xff0c;基于量子计算机超算架构进行算法开…

jspXMl标记语言基础

1.打开命令框进入数据库 打开eclipse创建需要连接的项目 粘贴驱动程序 查看驱动器 使用sql的包 int代表个 conlm代表列名 <%page import"java.sql.ResultSet"%> <%page import"java.sql.Statement"%> <%page import"java.sql.Connect…

蛋白聚乙二醇化修饰检测试剂盒

蛋白多肽因其高生物活性、高特异性等优点备受药物开发商和研究者的青睐。但分子量大、亲水性强、稳定性差等劣势限制了蛋白多肽在临床上的应用&#xff0c;特别是蛋白多肽作为一种异源蛋白具有很强的免疫原性&#xff0c;容易被机体免疫系统识别并清除&#xff0c;导致药物的血…

万物皆可监控(shell脚本监控TIDB-DM和DSG同步状态)

监控的方式有很多&#xff0c;常用的有zabbix和prometheus平台&#xff0c;理论上都可以做到对有状态服务的监控&#xff0c;因为我个人对这两个监控平台不是很熟悉&#xff0c;所以一般喜欢使用shell脚本来做监控&#xff1b; 纯oracle 数据库的监控推荐使用EMCC&#xff0c;…

前端面试题日常练-day12 【面试题】

题目 希望这些选择题能够帮助您进行前端面试的准备&#xff0c;答案在文末。 1. 在JavaScript中&#xff0c;以下哪个关键字用于声明一个变量&#xff1f; a) letb) varc) constd) all of the above2. 下面哪个方法可以用于将一个字符串转换为整数&#xff1f; a) toInteger(…

蓝桥杯备战15.完全二叉树的权值

P8681 [蓝桥杯 2019 省 AB] 完全二叉树的权值 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<bits/stdc.h> using namespace std; #define endl \n #define int long long const int N 2e510; int a[N]; signed main() {std::ios::sync_with_stdio(0),cin.ti…

C# Winform+Halcon结合标准视觉工具

介绍 winform与halcon结合标准化工具实例 软件架构 软件架构说明 基于NET6 WINFORMHALCON 实现标准化视觉检测工具 集成相机通讯 集成PLC通讯 TCP等常见通讯 支持常见halcon算子 图形采集blob分析高精度匹配颜色提取找几何体二维码提取OCR识别等等 。。。 安装教程 …

【Kafka】2.深入理解Kafka事件流平台及其核心概念

1.事件流(Event streaming) 事件流是人体中枢神经系统的数字化的等价物。它是构建“始终在线”世界的技术基础&#xff0c;在这个世界中&#xff0c;企业越来越多地被定义为软件化和自动化&#xff0c;而软件的用户本身也是软件。 从技术上讲&#xff0c;事件流是从数据库、传…

vue2 双向数据绑定的实现及原理

Oject.defineProperty() 是 JavaScript 中用于定义或修改对象的属性的方法&#xff0c;可以控制属性的特性&#xff08;如可枚举性、可配置性、可写性等&#xff09; Object.defineProperty(obj, prop, descriptor) obj&#xff1a;要在其上定义属性的对象。 prop&#xff1a;要…

P7222 [RC-04] 信息学竞赛

文章目录 题目[RC-04] 信息学竞赛题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示 思路AC代码 题目 [RC-04] 信息学竞赛 题目描述 小 R 今天学习了余角有关的数学知识&#xff0c;请你帮帮他计算一个角的余角吧&#xff01; 一个角的余角的计算公式如下&#…

SHELL编程(一)

目录 一、 Linux操作系统&#xff08;一&#xff09;内核与操作系统&#xff08;二&#xff09;操作系统的功能 二、Linux高级命令&#xff08;一&#xff09; 离线安装 dpkg1. 安装2. 使用3. 查看安装详细信息4. 安装路径5. 不完全删除6. 完全删除 &#xff08;二&#xff09;…

KNN算法用于回归分析

生成数据集 from sklearn.datasets import make_regression import matplotlib.pyplot as plt# 生成特征数量为1&#xff0c; 噪音为50的数据集 X, y make_regression(n_features1, n_informative1, noise50, random_state8)# 散点图 plt.scatter(X, y, c"orange",…

什么是TCP的粘包、拆包问题?

一、问题解析 TCP粘包和拆包问题是指在进行TCP通信时&#xff0c;因为TCP是面向流的&#xff0c;所以发送方在传输数据时可能会将多个小的数据包粘合在一起发送&#xff0c;而接收方则可能将这些数据包拆分成多个小的数据包进行接收&#xff0c;从而导致数据接收出现错误或者数…

uniapp swiper添加点击切换 上一张 下一张

<view click"switchPrev"><text>上一张</text> </view> <view click"switchNext"><text>下一张</text> </view> <swiper class"swiper" circular :current"current"> data() {…

MySQL数据库练习二

素材&#xff1a;表名&#xff1a;worker-- 表中字段均为中文&#xff0c;比如部门号、工资、职工号、参加工作等 CREATE TABLE worker (部门号 int(11) NOT NULL,职工号 int(11) NOT NULL,工作时间 date NOT NULL,工资 float(8,2) NOT NULL,政治面貌 varchar(10) NOT NULL DE…

欢乐钓鱼大师攻略大全,新手钓鱼入坑必备攻略!

《欢乐钓鱼大师》是一款深受玩家喜爱的钓鱼手游&#xff0c;在游戏中&#xff0c;玩家可以通过升级和更换鱼竿来享受钓鱼的乐趣&#xff0c;并有机会钓到各种稀有鱼类。然而&#xff0c;很多玩家在闯关过程中遇到了不少困难。为了帮助大家更好地掌握游戏技巧&#xff0c;小编特…

4 软件定义安全综合:使用c/s模式进行控制器数据安全交互管理

在SDN三层结构中&#xff0c;我们通过OpenFlow 协议可以控制数据转发设备的相关行为&#xff08;包括收集设备的信息&#xff09;&#xff0c;那么控制器上的数据能否通过应用层的程序进行管理调用呢&#xff1f; SDN&#xff08;软件定义网络&#xff09;的北向开发是指通过编…

ASUS Zenbook PE重装系统后一直转圈不断重启

问题描述&#xff1a; ASUS Zenbook PE重装系统后一直转圈不断重启 问题原因&#xff1a; RST驱动问题 解决办法&#xff1a; 使用U盘安装原版系统&#xff0c;安装过程中&#xff0c;发现磁盘页面没有不识别硬盘&#xff0c;此时选择加载驱动&#xff0c;加载RST驱动。一…

二进制搭建k8s

实验环境&#xff1a; k8s集群master01:192.168.1.11 k8s集群master02:192.168.1.22 master虚拟ip&#xff1a;192.168.1.100 k8s集群node01:192.168.1.33 k8s集群node01:192.168.1.44 nginxkeepalive01&#xff08;master&#xff09;:192.168.1.55 nginxkeepalive02&a…

渲染农场是什么意思?瑞云渲染为你解答

渲染农场是一种通过集合多台计算机的计算能力来加速图像渲染过程的系统。它尤其适用于动画、电影特效和高端视觉效果的制作&#xff0c;这些领域通常需要处理非常复杂和计算密集型的渲染任务。 渲染农场就是一大群电脑&#xff0c;他们一起可以快速渲染出漂亮的图像。在做动画片…