元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
算法基础
▶
复杂度分析
时间复杂度
空间复杂度
渐进符号
▶
算法思想
分治法
贪心算法
回溯法
概率算法
枚举算法
递推算法
递归算法
动态规划
分支限界法
模拟算法
▶
算法分析
正确性证明
性能优化
算法比较
▶
搜索算法
▶
基本搜索
顺序搜索
二分搜索
插值搜索
▶
图搜索
深度优先搜索
广度优先搜索
启发式搜索
▶
高级搜索
双向搜索
A*算法
模式匹配
▶
排序算法
▶
比较类排序
冒泡排序
快速排序
归并排序
插入排序
选择排序
▶
非比较类排序
计数排序
基数排序
桶排序
▶
高级排序
堆排序
希尔排序
外部排序
拓扑排序
▶
图论算法
▶
图的表示
邻接矩阵
邻接表
边集数组
▶
最短路径
Dijkstra算法
Floyd算法
Bellman-Ford算法
最短路径概述
▶
生成树
Prim算法
Kruskal算法
并查集
最小生成树
▶
图的连通性
强连通分量
割点与桥
双连通分量
欧拉路径
▶
动态规划
▶
基础概念
最优子结构
重叠子问题
状态转移方程
▶
经典问题
背包问题
最长公共子序列
编辑距离
▶
优化技巧
空间优化
状态压缩
区间动态规划
▶
字符串算法
▶
字符串匹配
KMP算法
Boyer-Moore算法
Sunday算法
▶
字符串处理
字典树
后缀数组
字符串哈希
▶
压缩算法
游程编码
Huffman编码
LZ77算法
发布时间:
2025-03-21 18:26
↑
☰
# 深度优先搜索 深度优先搜索(Depth-First Search,简称DFS)是一种用于遍历或搜索树或图的算法。该算法从根节点开始,沿着一条路径一直探索到最深处,直到无法继续为止,然后回溯到上一个节点,继续探索其他路径。 ## 基本原理 深度优先搜索的工作原理如下: 1. 从起始节点开始 2. 选择一个未访问的相邻节点 3. 递归地探索这个节点 4. 如果没有未访问的相邻节点,则回溯 5. 重复步骤2-4,直到所有节点都被访问 ## 代码实现 ### 递归实现(图) ```python class Graph: def __init__(self): self.graph = {} # 邻接表表示 def add_edge(self, u, v): if u not in self.graph: self.graph[u] = [] self.graph[u].append(v) def dfs(self, start, visited=None): if visited is None: visited = set() visited.add(start) print(start, end=' ') # 递归访问所有未访问的相邻节点 for neighbor in self.graph.get(start, []): if neighbor not in visited: self.dfs(neighbor, visited) # 使用示例 graph = Graph() graph.add_edge(0, 1) graph.add_edge(0, 2) graph.add_edge(1, 2) graph.add_edge(2, 0) graph.add_edge(2, 3) graph.add_edge(3, 3) print("深度优先遍历(从节点0开始):") graph.dfs(0) ``` ### 迭代实现(使用栈) ```python def dfs_iterative(graph, start): visited = set() stack = [start] while stack: vertex = stack.pop() if vertex not in visited: visited.add(vertex) print(vertex, end=' ') # 将未访问的相邻节点压入栈中 for neighbor in graph[vertex]: if neighbor not in visited: stack.append(neighbor) # 使用示例 graph = { 0: [1, 2], 1: [2], 2: [0, 3], 3: [3] } print("深度优先遍历(从节点0开始):") dfs_iterative(graph, 0) ``` ## 性能分析 ### 时间复杂度 - 邻接表表示:O(V + E),其中V是顶点数,E是边数 - 邻接矩阵表示:O(V²) ### 空间复杂度 - 递归实现:O(V),递归调用栈的深度 - 迭代实现:O(V),用于存储访问状态和栈 ### 优缺点分析 优点: 1. 实现简单,容易理解 2. 内存占用相对较小 3. 可以找到离起点较远的节点 4. 适合搜索全部解决方案 缺点: 1. 可能陷入很深的分支 2. 不一定能找到最短路径 3. 对于大规模图可能导致栈溢出 ## 应用场景 1. 迷宫问题 2. 拓扑排序 3. 连通性分析 4. 路径查找 ## 实际应用示例 ### 1. 迷宫求解 ```python def solve_maze(maze, start, end): def is_valid(x, y): return (0 <= x < len(maze) and 0 <= y < len(maze[0]) and maze[x][y] == 0) def dfs(x, y, path): if (x, y) == end: return path # 四个方向:上、右、下、左 directions = [(-1, 0), (0, 1), (1, 0), (0, -1)] for dx, dy in directions: next_x, next_y = x + dx, y + dy if (is_valid(next_x, next_y) and (next_x, next_y) not in visited): visited.add((next_x, next_y)) result = dfs(next_x, next_y, path + [(next_x, next_y)]) if result: return result visited.remove((next_x, next_y)) return None visited = {start} return dfs(start[0], start[1], [start]) # 使用示例 maze = [ [0, 0, 0, 1], [1, 1, 0, 1], [0, 0, 0, 0], [1, 1, 1, 0] ] start = (0, 0) end = (3, 3) path = solve_maze(maze, start, end) if path: print("找到路径:", path) else: print("没有找到路径") ``` ### 2. 拓扑排序 ```python def topological_sort(graph): def dfs(node): if node in visited: return visited.add(node) # 递归访问所有依赖节点 for neighbor in graph.get(node, []): dfs(neighbor) # 将节点加入结果列表 result.insert(0, node) visited = set() result = [] # 对每个节点执行DFS for node in graph: if node not in visited: dfs(node) return result # 使用示例 graph = { 'A': ['C'], 'B': ['C', 'D'], 'C': ['E'], 'D': ['F'], 'E': ['H', 'F'], 'F': ['G'], 'G': [], 'H': [] } order = topological_sort(graph) print("拓扑排序结果:", order) ``` ## 优化技巧 1. 避免重复访问 ```python def dfs_with_pruning(graph, start, visited=None): if visited is None: visited = set() if start in visited: return visited.add(start) print(start, end=' ') for neighbor in graph.get(start, []): dfs_with_pruning(graph, neighbor, visited) ``` 2. 限制搜索深度 ```python def dfs_with_depth_limit(graph, start, depth_limit): def dfs(node, depth): if depth > depth_limit: return if node not in visited: visited.add(node) print(node, end=' ') for neighbor in graph.get(node, []): dfs(neighbor, depth + 1) visited = set() dfs(start, 0) ``` 3. 记忆化搜索 ```python def dfs_with_memo(graph, start): memo = {} def dfs(node): if node in memo: return memo[node] result = set([node]) for neighbor in graph.get(node, []): result.update(dfs(neighbor)) memo[node] = result return result return dfs(start) ``` ## 常见问题和解决方案 1. 环检测 ```python def has_cycle(graph): def dfs(node): visited.add(node) path.add(node) for neighbor in graph.get(node, []): if neighbor in path: return True if neighbor not in visited: if dfs(neighbor): return True path.remove(node) return False visited = set() path = set() for node in graph: if node not in visited: if dfs(node): return True return False ``` 2. 双向DFS ```python def bidirectional_dfs(graph, start, end): def dfs(node, visited, target, forward): if node in opposite_visited: return True visited.add(node) neighbors = graph.get(node, []) if forward else [ n for n in graph if node in graph.get(n, []) ] for neighbor in neighbors: if neighbor not in visited: if dfs(neighbor, visited, target, forward): return True return False forward_visited = set() backward_visited = set() opposite_visited = backward_visited return dfs(start, forward_visited, end, True) ``` ## 总结 深度优先搜索是一种重要的图遍历算法,它通过递归或栈的方式实现对图的深度优先遍历。DFS的主要特点是沿着一条路径一直探索到底,然后回溯到上一个节点继续探索其他路径。这种特性使它特别适合用于解决迷宫问题、拓扑排序等需要完整探索所有可能路径的问题。 在实际应用中,我们需要根据具体问题选择合适的实现方式,并考虑使用适当的优化技巧来提高算法的效率。同时,要注意处理环检测、深度限制等常见问题,确保算法的正确性和稳定性。