2026-10-23 09:45:24
在JavaScript中,图的遍历主要通过深度优先搜索(DFS)和广度优先搜索(BFS)实现,两者在实现方式、应用场景及性能优化上存在显著差异。
一、DFS与BFS的实现方式DFS(深度优先搜索)
实现原理:通过递归或栈模拟“一条路走到黑”的搜索方式,优先深入访问未探索的分支。
代码示例:depthFirstSearch(startNode) { const visited = {}; const result = []; const traverse = (vertex) => { if (!vertex) return; visited[vertex] = true; result.push(vertex); this.adjacencyList[vertex].forEach(neighbor => { if (!visited[neighbor]) traverse(neighbor); }); }; traverse(startNode); return result;}
特点:递归实现简洁,但深度过大时可能导致栈溢出;内存占用较低(仅维护当前路径)。
BFS(广度优先搜索)
实现原理:利用队列逐层扩展,先访问起始节点的所有邻居,再依次访问邻居的邻居。
代码示例:breadthFirstSearch(startNode) { const visited = {}; const result = []; const queue = [startNode]; visited[startNode] = true; while (queue.length > 0) { const vertex = queue.shift(); result.push(vertex); this.adjacencyList[vertex].forEach(neighbor => { if (!visited[neighbor]) { visited[neighbor] = true; queue.push(neighbor); } }); } return result;}
特点:队列实现稳定,适合分层搜索;内存占用较高(需存储整层节点)。
DFS:深入优先,适合探索所有可能路径(如迷宫求解)。
BFS:广度优先,适合寻找最短路径(如社交网络关系链)。
DFS:仅维护当前路径,内存占用低,但递归深度过大时可能栈溢出。
BFS:需存储整层节点,内存占用高,但无栈溢出风险。
DFS:不保证最短路径,但能快速找到是否存在路径。
BFS:保证首次找到的路径为最短路径。
DFS适用场景
路径存在性问题:如检查图中是否存在从A到B的路径。
拓扑排序:确定有向无环图的节点执行顺序(如任务调度)。
连通分量检测:识别图中的独立子图(如社交网络中的群组)。
BFS适用场景
最短路径问题:如计算两个节点之间的最少跳转次数。
层级遍历:按距离起始节点的层数处理节点(如树形结构的逐层渲染)。
广播传播:模拟信息从中心节点向外扩散的过程(如病毒传播模型)。
使用DFS确定组件加载顺序,避免循环依赖(如Webpack打包优化)。
通过BFS管理页面跳转历史,实现前进/后退功能(如React Router的导航栈)。
遍历树或图结构,生成可视化布局(如调试工具中的状态树展示)。
DFS实现迷宫寻路,BFS优化NPC移动路径(如简单AI的寻路算法)。
稀疏图优先使用邻接表(节省空间),稠密图可考虑邻接矩阵(快速访问)。
通过visited对象或集合标记已访问节点,减少冗余计算。
提前终止无效搜索(如DFS中目标节点已找到时停止递归)。
使用显式栈模拟DFS,避免递归深度过大(示例如下):iterativeDFS(startNode) { const visited = {}; const result = []; const stack = [startNode]; while (stack.length > 0) { const vertex = stack.pop(); if (visited[vertex]) continue; visited[vertex] = true; result.push(vertex); // 逆序压栈以保证顺序正确 this.adjacencyList[vertex].reverse().forEach(neighbor => { if (!visited[neighbor]) stack.push(neighbor); }); } return result;}
将图分割为子图,并行遍历(如Web Workers处理大规模数据)。
对静态图预计算遍历结果,避免重复计算(如静态路由配置)。