当前位置: 首页 > article >正文

广度优先搜索(BFS) vs 深度优先搜索(DFS):算法对比与 C++ 实现

目录

一、BFS 和 DFS 的核心思想

1. BFS(广度优先搜索)

2. DFS(深度优先搜索)

二、BFS 和 DFS 的对比

三、C++ 代码实现

1. BFS 实现(邻接表表示的无向图)

2. DFS 实现(递归与迭代两种方式)

四、关键细节说明

1. BFS 的关键点

2. DFS 的关键点

五、应用场景对比

六、总结


一、BFS 和 DFS 的核心思想

1. BFS(广度优先搜索)

  • 核心思想:按“层级”逐层遍历,先访问离起点最近的节点,再逐步向外扩散。

  • 类比:类似水波扩散,一层一层向外推进。

  • 数据结构:队列(FIFO)。

  • 适用场景:最短路径(未加权图)、社交网络层级关系、迷宫最短路径。

2. DFS(深度优先搜索)

  • 核心思想:沿着一条路径尽可能深入,直到无法继续时回溯,尝试其他分支。

  • 类比:走迷宫时,遇到岔路选择一条路走到头,再返回选择其他路。

  • 数据结构:栈(LIFO)或递归调用栈。

  • 适用场景:拓扑排序、连通性检测、回溯问题(如八皇后)、图的环路检测。


二、BFS 和 DFS 的对比

特性BFSDFS
遍历顺序层级遍历(近到远)深度优先(一条路走到黑)
数据结构队列(先进先出)栈(后进先出)或递归
空间复杂度O(N)(最坏情况,如完全二叉树)O(H)(H为树的高度,平衡树时为 O(logN))
时间复杂度O(N + E)(N为节点数,E为边数)同左
最短路径天然支持(未加权图)需额外处理(如记录路径长度)
内存消耗较高(存储每一层节点)较低(仅存储当前路径)
实现复杂度简单(固定队列操作)递归简单,迭代需显式栈

三、C++ 代码实现

1. BFS 实现(邻接表表示的无向图)

#include <iostream>
#include <queue>
#include <vector>
using namespace std;

void bfs(const vector<vector<int>>& graph, int start) {
    vector<bool> visited(graph.size(), false);
    queue<int> q;
    q.push(start);
    visited[start] = true;

    while (!q.empty()) {
        int node = q.front();
        q.pop();
        cout << node << " "; // 访问节点

        // 遍历当前节点的所有邻居
        for (int neighbor : graph[node]) {
            if (!visited[neighbor]) {
                visited[neighbor] = true;
                q.push(neighbor);
            }
        }
    }
}

// 示例图结构
vector<vector<int>> graph = {
    {1, 2},     // 节点0的邻居
    {0, 3, 4},  // 节点1的邻居
    {0, 5, 6},  // 节点2的邻居
    {1},        // 节点3的邻居
    {1},        // 节点4的邻居
    {2},        // 节点5的邻居
    {2}         // 节点6的邻居
};

int main() {
    cout << "BFS遍历结果: ";
    bfs(graph, 0); // 输出: 0 1 2 3 4 5 6
    return 0;
}

2. DFS 实现(递归与迭代两种方式)

// 递归实现
void dfsRecursive(const vector<vector<int>>& graph, int node, vector<bool>& visited) {
    visited[node] = true;
    cout << node << " "; // 访问节点

    for (int neighbor : graph[node]) {
        if (!visited[neighbor]) {
            dfsRecursive(graph, neighbor, visited);
        }
    }
}

// 迭代实现(显式栈)
void dfsIterative(const vector<vector<int>>& graph, int start) {
    vector<bool> visited(graph.size(), false);
    stack<int> s;
    s.push(start);
    visited[start] = true;

    while (!s.empty()) {
        int node = s.top();
        s.pop();
        cout << node << " ";

        // 反向遍历邻居以保证与递归顺序一致
        for (auto it = graph[node].rbegin(); it != graph[node].rend(); ++it) {
            if (!visited[*it]) {
                visited[*it] = true;
                s.push(*it);
            }
        }
    }
}

int main() {
    cout << "DFS递归遍历结果: ";
    vector<bool> visited(graph.size(), false);
    dfsRecursive(graph, 0, visited); // 输出: 0 1 3 4 2 5 6

    cout << "\nDFS迭代遍历结果: ";
    dfsIterative(graph, 0);          // 输出: 0 1 3 4 2 5 6
    return 0;
}

四、关键细节说明

1. BFS 的关键点

  • 队列操作:每次从队头取出节点,并将未访问的邻居加入队尾。

  • 最短路径:BFS 首次访问到目标节点时,路径一定是最短的(适用于未加权图)。

  • 空间复杂度:最坏情况下需存储所有节点(如完全二叉树最后一层)。

2. DFS 的关键点

  • 递归与栈:递归隐式使用系统栈,迭代显式使用栈。

  • 遍历顺序:迭代实现中,若按正序访问邻居,结果可能与递归顺序不同(需反向遍历邻居)。

  • 应用场景:适合探索所有可能性(如回溯问题),但可能陷入深层分支无法及时返回。


五、应用场景对比

问题类型推荐算法原因
未加权图最短路径BFS天然支持最短路径
图的连通性检测DFS/BFS二者均可快速遍历所有连通节点
拓扑排序DFS天然支持后序遍历的逆序
迷宫所有路径DFS回溯特性适合探索所有可能路径
社交网络层级关系分析BFS按层遍历符合实际场景
检测环路DFS通过回溯标记路径,容易检测重复访问

六、总结

  • BFS 适合“广度优先”问题,如最短路径;DFS 适合“深度优先”问题,如回溯和连通性。

  • 代码实现:BFS 用队列,DFS 用栈或递归,注意遍历顺序和空间消耗。

  • 选择依据:根据问题特性(如是否需要最短路径、内存限制)选择算法。


http://www.kler.cn/a/597644.html

相关文章:

  • 洛谷 P10108 [GESP202312 六级] 闯关游戏 题解
  • Android Studio控制台中文乱码解决方案
  • Webpack vs Vite:深度对比与实战示例,如何选择最佳构建工具?
  • LeetCode热题100精讲——Top1:两数之和【哈希】
  • 如何编写一个Spring Boot Starter
  • Ubuntu YOLO5 环境安装
  • UI设计中的大数据可视化:解锁数据背后的秘密
  • 基于深度学习的图像分割项目实践:从理论到应用
  • 基于WebAssembly的浏览器密码套件
  • 【技术选型】三大 Python Web 框架全面对比
  • React学习(进阶)
  • github如何为开源项目作出贡献
  • 为什么后端路由需要携带 /api 作为前缀?前端如何设置基础路径 /api?
  • Python推导式深入解析
  • React Native进阶(六十一): WebView 替代方案 react-native-webview 应用详解
  • 使用外部事件检测接入 CDH 大数据管理平台告警
  • 除自身以外数组的乘积——面试经典150题(力扣)
  • 基于Python+Ollama DeepSeek与MySQL进行数据分析探索
  • Rocky9.5基于sealos快速部署k8s集群
  • OpenHarmony子系统开发 - 电源管理(二)