news 2026/9/10 13:35:09

深度优先搜索(DFS)与广度优先搜索(BFS)核心原理与应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深度优先搜索(DFS)与广度优先搜索(BFS)核心原理与应用

1. 深度优先搜索(DFS)与广度优先搜索(BFS)核心原理剖析

在算法与数据结构领域,DFS和BFS是两种最基础的图遍历策略。我第一次接触这两个概念是在解决迷宫问题时——DFS像探险家执着地探索每条岔路直到尽头,而BFS像雷达波一样层层推进确保最短路径。这两种截然不同的思维方式,构成了算法世界的阴阳两面。

DFS采用"不撞南墙不回头"的纵向搜索策略,其核心在于递归和栈的运用。当访问某个顶点时,算法会立即深入探索它的第一个未访问邻接点,直到没有未访问节点时才回溯。这种特性使其天然适合解决拓扑排序、连通分量检测等问题。而BFS则采用"广撒网"的横向搜索策略,借助队列实现层级遍历,这种一层层向外扩张的特性,使其成为最短路径问题的首选方案。

关键区别:DFS的内存消耗取决于图的高度(递归深度),而BFS的内存消耗取决于图的宽度(队列长度)。在树形结构中,DFS的空间复杂度通常是O(h),BFS则是O(w),其中h为树高,w为最宽层的节点数。

2. 算法实现细节与代码模板

2.1 DFS的递归与非递归实现

递归版DFS是最直观的实现方式,以下是以二叉树为例的Python模板:

def dfs_recursive(node): if not node: return # 前序遍历处理 process(node.val) dfs_recursive(node.left) # 中序遍历位置 dfs_recursive(node.right) # 后序遍历位置

非递归实现需要显式使用栈,这是很多面试考察的重点:

def dfs_iterative(root): stack = [root] visited = set() while stack: node = stack.pop() if node not in visited: visited.add(node) process(node) # 注意压栈顺序(保证左子树先处理) for neighbor in [node.right, node.left]: if neighbor: stack.append(neighbor)

2.2 BFS的队列实现与层级控制

标准BFS模板如下,特别注意层级遍历的写法:

from collections import deque def bfs(root): queue = deque([root]) visited = set(root) level = 0 while queue: # 记录当前层节点数 size = len(queue) for _ in range(size): # 处理当前层 node = queue.popleft() process(node) for neighbor in [node.left, node.right]: if neighbor and neighbor not in visited: visited.add(neighbor) queue.append(neighbor) level += 1 # 完成一层遍历

实战技巧:BFS的层级记录(level变量)是解决最短路径问题的关键。在二维矩阵遍历中,常用dx=[-1,1,0,0], dy=[0,0,-1,1]表示四个方向的移动。

3. 典型应用场景对比分析

3.1 DFS的适用场景

  • 拓扑排序:课程表问题(LeetCode 207)
  • 连通分量:岛屿数量问题(LeetCode 200)
  • 回溯算法:全排列(LeetCode 46)
  • 记忆化搜索:滑雪场最长路径(LeetCode 329)

以岛屿问题为例的DFS解法:

def numIslands(grid): def dfs(i, j): if not (0<=i<m and 0<=j<n) or grid[i][j]!='1': return grid[i][j] = '0' # 已访问标记 for di,dj in [(1,0),(-1,0),(0,1),(0,-1)]: dfs(i+di, j+dj) count = 0 m, n = len(grid), len(grid[0]) for i in range(m): for j in range(n): if grid[i][j] == '1': count += 1 dfs(i, j) return count

3.2 BFS的适用场景

  • 最短路径:迷宫最短路径(LeetCode 1091)
  • 层级遍历:二叉树层级输出(LeetCode 102)
  • 扩散传播:腐烂的橘子(LeetCode 994)
  • 状态转换:开密码锁(LeetCode 752)

以二叉树层级遍历为例:

def levelOrder(root): if not root: return [] res = [] queue = deque([root]) while queue: level = [] for _ in range(len(queue)): node = queue.popleft() level.append(node.val) if node.left: queue.append(node.left) if node.right: queue.append(node.right) res.append(level) return res

4. 性能优化与常见陷阱

4.1 剪枝优化策略

在DFS的回溯算法中,剪枝能大幅提升效率:

def permute(nums): res = [] def backtrack(path, used): if len(path) == len(nums): res.append(path[:]) return for i in range(len(nums)): if not used[i]: # 剪枝条件示例:跳过重复排列 if i>0 and nums[i]==nums[i-1] and not used[i-1]: continue used[i] = True backtrack(path+[nums[i]], used) used[i] = False nums.sort() # 便于剪枝 backtrack([], [False]*len(nums)) return res

4.2 双向BFS优化

当起点和终点都已知时,双向BFS能指数级减少搜索空间:

def openLock(deadends, target): dead = set(deadends) if "0000" in dead: return -1 def neighbors(node): for i in range(4): x = int(node[i]) for d in (-1, 1): y = (x + d) % 10 yield node[:i] + str(y) + node[i+1:] visited = set() q1, q2 = {"0000"}, {target} steps = 0 while q1 and q2: if len(q1) > len(q2): # 总是扩展较小的队列 q1, q2 = q2, q1 temp = set() for node in q1: if node in dead: continue if node in q2: return steps visited.add(node) for neighbor in neighbors(node): if neighbor not in visited: temp.add(neighbor) steps += 1 q1 = temp return -1

4.3 高频易错点

  1. DFS栈溢出:当递归深度超过1000层时(如链状图),Python会抛出RecursionError。解决方法:

    • 改用非递归实现
    • 设置sys.setrecursionlimit(100000)
  2. BFS未标记已访问:会导致重复入队和死循环。必须遵循"入队即标记"原则:

    queue.append(start) visited.add(start) # 立即标记
  3. 二维矩阵遍历边界检查:四种常见写法差异:

    # 方法1:提前判断 if 0<=ni<m and 0<=nj<n and not visited[ni][nj]: dfs(ni, nj) # 方法2:在递归开始处判断(更推荐) def dfs(i, j): if not (0<=i<m and 0<=j<n) or visited[i][j]: return ...

5. 工业级应用案例

5.1 文件系统遍历的DFS实现

模拟Linux的find命令实现:

import os def find_files(path, pattern): matches = [] for root, dirs, files in os.walk(path): # 内置DFS for file in files: if file.endswith(pattern): matches.append(os.path.join(root, file)) return matches # 等效手动实现 def find_files_manual(path, pattern): stack = [path] res = [] while stack: curr = stack.pop() try: entries = os.listdir(curr) except PermissionError: continue for entry in entries: full_path = os.path.join(curr, entry) if os.path.isdir(full_path): stack.append(full_path) elif entry.endswith(pattern): res.append(full_path) return res

5.2 网络爬虫的BFS实现

简单的网页爬虫实现:

import requests from urllib.parse import urljoin from collections import deque def web_crawler(start_url, max_depth=3): visited = set() queue = deque([(start_url, 0)]) results = [] while queue: url, depth = queue.popleft() if depth > max_depth: continue try: response = requests.get(url, timeout=3) if response.status_code == 200: results.append(url) soup = BeautifulSoup(response.text, 'html.parser') for link in soup.find_all('a', href=True): absolute_url = urljoin(url, link['href']) if absolute_url.startswith('http') and absolute_url not in visited: visited.add(absolute_url) queue.append((absolute_url, depth+1)) except Exception as e: print(f"Error fetching {url}: {e}") return results

5.3 社交网络关系分析

用BFS实现三度人脉查找:

def find_connections(graph, start, max_degree=3): from collections import defaultdict levels = defaultdict(list) visited = {start: 0} queue = deque([(start, 0)]) while queue: person, degree = queue.popleft() if degree > max_degree: continue levels[degree].append(person) for friend in graph.get(person, []): if friend not in visited: visited[friend] = degree + 1 queue.append((friend, degree + 1)) return levels

在实际工程中,当处理超大规模图数据时,通常会采用以下优化手段:

  1. 对DFS使用迭代深化搜索(IDS)
  2. 对BFS使用分层采样或随机游走
  3. 结合并行计算框架如Spark GraphX
  4. 对社交网络使用近似算法(如HyperANF)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 13:34:50

EmotionVGGnet:面向边缘设备的轻量级面部情绪识别CNN架构

简介&#xff1a;本资源是一份基于VGGNet架构的情绪识别Python实战项目&#xff0c;面向深度学习初学者与计算机视觉方向实践者&#xff0c;聚焦图像模态情感分类任务&#xff0c;提供从数据构建、模型搭建到训练评估的完整闭环方案。压缩包共11个文件&#xff0c;含6个核心Pyt…

作者头像 李华
网站建设 2026/9/10 13:33:57

CANN/ge MatchResult构造函数和析构函数

MatchResult构造函数和析构函数 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTo…

作者头像 李华
网站建设 2026/9/10 13:33:27

网盘直链解析完全指南:LinkSwift 四步跑通九大网盘真实直链

网盘直链解析完全指南&#xff1a;LinkSwift 四步跑通九大网盘真实直链 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 /…

作者头像 李华