深度遍历(Depth-First Search, DFS)和广度遍历(Breadth-First Search, BFS)是图和树结构中常用的遍历方法。它们在访问节点的顺序和策略上有明显的不同。以下是它们的主要区别:
1. 深度遍历(DFS)
-
策略:优先深入到每个分支的尽头,然后回溯到上一个节点,继续探索其他未访问的分支。
-
数据结构:通常使用栈(可以是显式栈或递归调用的系统栈)来实现。
-
特点:
- 遍历顺序:沿着树的深度方向进行,先访问子节点再访问兄弟节点。
- 路径:可能找到到目标节点的一条路径,但不一定是最短路径。
- 空间复杂度:在最坏情况下,栈的空间复杂度是 O(h),其中 h 是树的高度。
-
示例:
function dfs(node, visited) { if (node === null) return; console.log(node.value); // 访问节点 visited.add(node); // 标记为已访问 for (const neighbor of node.neighbors) { if (!visited.has(neighbor)) { dfs(neighbor, visited); } } }
2. 广度遍历(BFS)
-
策略:从根节点开始,逐层访问每个节点的所有直接子节点,然后再访问这些子节点的子节点,以此类推。
-
数据结构:通常使用队列来实现。
-
特点:
- 遍历顺序:先访问当前层的所有节点,然后再访问下一层节点。
- 路径:总是找到到目标节点的最短路径(如果图中的边权值相等)。
- 空间复杂度:在最坏情况下,队列的空间复杂度是 O(w),其中 w 是图中最大宽度(即最大层级节点数)。
-
示例:
function bfs(startNode) { const queue = [startNode]; const visited = new Set(); visited.add(startNode); while (queue.length > 0) { const node = queue.shift(); // 从队列前端取出节点 console.log(node.value); // 访问节点 for (const neighbor of node.neighbors) { if (!visited.has(neighbor)) { visited.add(neighbor); queue.push(neighbor); // 将未访问的邻居添加到队列 } } } }