图的遍历:深度优先搜索(DFS)和广度优先搜索(BFS)

图的遍历:深度优先搜索(DFS)和广度优先搜索(BFS)

1. 什么是图?

在计算机科学中,(Graph)是一种数据结构,由节点(也称为顶点)和连接这些节点的组成。图可以用来表示各种关系,比如社交网络中的朋友关系、地图中的路径、网络中的设备连接等。

图分为以下几种类型:

  • 无向图:图中的边没有方向,表示节点之间的关系是对称的。
  • 有向图:图中的边有方向,表示节点之间的关系是单向的。
  • 加权图:图中的边带有权重,表示连接两个节点的代价、距离或其他度量。
  • 无环图:图中没有形成环路。
  • 连通图:图中的任意两个节点之间都有路径相连。

2. 如何判断是图?

图是由节点和连接这些节点的边组成的数据结构。要判断一个结构是否是图,我们可以检查以下特征:

  1. 节点集合:图由一组节点(顶点)组成,通常使用 V 表示。
  2. 边集合:图还包含一组边,边是连接两个节点的关系,通常使用 E 表示。
  3. 连接性:在图中,节点之间的连接性由边来表示,这些连接可以是单向或双向的。

在图的表示中,通常使用邻接表(Adjacency List)或邻接矩阵(Adjacency Matrix)来表示图的结构。

3. 图的遍历

图的遍历指的是从图中的某一个节点开始,访问所有与之相连的节点。常见的图遍历算法有两种:深度优先搜索(DFS)广度优先搜索(BFS)

3.1 深度优先搜索(DFS)

深度优先搜索(Depth-First Search, DFS)是一种从图的起始节点出发,尽可能深的访问图的搜索算法。它优先访问未访问的子节点,直到无法再深入为止,然后回溯到前一个节点继续搜索未访问的其他节点。

DFS 可以使用 递归迭代 两种方式实现。

3.1.1 递归实现 DFS

递归实现 DFS 通过递归函数的调用栈来模拟对图的深度优先遍历。

递归代码示例

#include <vector>
#include <iostream>

void dfs(int node, std::vector<bool>& visited, const std::vector<std::vector<int>>& graph) {
    visited[node] = true;
    std::cout << node << " "; // 访问节点
    
    // 访问相邻节点
    for (int neighbor : graph[node]) {
        if (!visited[neighbor]) {
            dfs(neighbor, visited, graph);
        }
    }
}

int main() {
    // 示例图(无向图)
    std::vector<std::vector<int>> graph = {
        {1, 2},    // 0 -> 1, 2
        {0, 3, 4}, // 1 -> 0, 3, 4
        {0, 5, 6}, // 2 -> 0, 5, 6
        {1},       // 3 -> 1
        {1},       // 4 -> 1
        {2},       // 5 -> 2
        {2}        // 6 -> 2
    };

    std::vector<bool> visited(graph.size(), false);
    dfs(0, visited, graph); // 从节点0开始DFS
    return 0;
}

递归 DFS 的执行过程

  • 从节点 0 开始,访问节点 0,标记为已访问。
  • 访问节点 0 的邻居 1,递归调用进入节点 1
  • 访问节点 1 的邻居 0(已访问,跳过),然后访问 34
  • 递归完成后,回溯到节点 0,访问节点 2,然后访问 56

输出结果0 1 3 4 2 5 6

3.1.2 迭代实现 DFS

迭代实现 DFS 使用显式的栈来模拟递归调用栈的行为。

迭代代码示例

#include <vector>
#include <stack>
#include <iostream>

void dfs_iterative(int start, const std::vector<std::vector<int>>& graph) {
    std::vector<bool> visited(graph.size(), false);
    std::stack<int> stack;
    
    stack.push(start);
    
    while (!stack.empty()) {
        int node = stack.top();
        stack.pop();
        
        if (!visited[node]) {
            visited[node] = true;
            std::cout << node << " "; // 访问节点
            
            // 将邻居节点压入栈中(逆序保证DFS的顺序性)
            for (auto it = graph[node].rbegin(); it != graph[node].rend(); ++it) {
                if (!visited[*it]) {
                    stack.push(*it);
                }
            }
        }
    }
}

int main() {
    // 示例图(无向图)
    std::vector<std::vector<int>> graph = {
        {1, 2},    // 0 -> 1, 2
        {0, 3, 4}, // 1 -> 0, 3, 4
        {0, 5, 6}, // 2 -> 0, 5, 6
        {1},       // 3 -> 1
        {1},       // 4 -> 1
        {2},       // 5 -> 2
        {2}        // 6 -> 2
    };

    dfs_iterative(0, graph); // 从节点0开始DFS
    return 0;
}

迭代 DFS 的执行过程

  • 从节点 0 开始,将 0 压入栈中。
  • 弹出栈顶节点 0 并访问,压入其邻居 21
  • 弹出栈顶节点 1 并访问,压入其邻居 43
  • 继续弹出并访问,直至所有节点访问完毕。

输出结果0 1 3 4 2 5 6

3.2 广度优先搜索(BFS)

广度优先搜索(Breadth-First Search, BFS)是一种从图的起始节点出发,优先访问距离起始节点最近的节点的搜索算法。它使用队列来维护访问顺序,逐层扩展,直到访问完所有节点。

BFS 一般使用 迭代 的方式实现。

3.2.1 迭代实现 BFS

迭代代码示例

#include <vector>
#include <queue>
#include <iostream>

void bfs(int start, const std::vector<std::vector<int>>& graph) {
    std::vector<bool> visited(graph.size(), false);
    std::queue<int> queue;
    
    queue.push(start);
    visited[start] = true;
    
    while (!queue.empty()) {
        int node = queue.front();
        queue.pop();
        
        std::cout << node << " "; // 访问节点
        
        // 将所有未访问的邻居节点加入队列
        for (int neighbor : graph[node]) {
            if (!visited[neighbor]) {
                visited[neighbor] = true;
                queue.push(neighbor);
            }
        }
    }
}

int main() {
    // 示例图(无向图)
    std::vector<std::vector<int>> graph = {
        {1, 2},    // 0 -> 1, 2
        {0, 3, 4}, // 1 -> 0, 3, 4
        {0, 5, 6}, // 2 -> 0, 5, 6
        {1},       // 3 -> 1
        {1},       // 4 -> 1
        {2},       // 5 -> 2
        {2}        // 6 -> 2
    };

    bfs(0, graph); // 从节点0开始BFS
    return 0;
}

BFS 的执行过程

  • 从节点 0 开始,将 0 压入队列。
  • 弹出队列前端的节点 0 并访问,压入其邻居 12
  • 继续弹出并访问队列前端的节点,直至所有节点访问完毕。

输出结果0 1 2 3 4 5 6

4. DFS 和 BFS 的区别

  • DFS
    • 优先访问深层节点。
    • 使用栈(递归调用栈或显式

栈)实现。

  • 适合用于搜索路径、检查连通性、解决迷宫等问题。

  • BFS

    • 优先访问同一层的节点。
    • 使用队列实现。
    • 适合用于寻找最短路径、层次遍历等问题。

5. 示例分析

5.1 图结构

以以下无向图为例,来解释 DFS 和 BFS 的过程:

     0
    / \
   1   2
  / \ / \
 3   4   5
  • 节点0, 1, 2, 3, 4, 5
    • 0 连接 12
    • 1 连接 34
    • 2 连接 5
5.2 深度优先搜索(DFS)
  • DFS 递归

    • 0 出发,访问 0 -> 1 -> 3(回溯) -> 4(回溯) -> 2 -> 5
  • DFS 迭代

    • 0 出发,访问 0 -> 2 -> 5(回溯) -> 1 -> 4(回溯) -> 3
5.3 广度优先搜索(BFS)
  • BFS
    • 0 出发,访问 0 -> 1 -> 2 -> 3 -> 4 -> 5

6. 总结

在解决图遍历问题时,DFS 和 BFS 是两种非常有用的搜索策略。DFS 更适合用于需要深度探索的场景,如路径查找或连通性问题;BFS 则更适合用于层次遍历或寻找最短路径的场景。理解这两种算法及其实现方式,对于解决复杂的图问题是非常重要的。
程中更上一层楼。

C++中实现遍历可以使用深度优先搜索(DFS)广度优先搜索(BFS)两种算法深度优先搜索(DFS): ``` #include <iostream> #include <vector> #include <stack> using namespace std; void DFS(vector<vector<int>>& graph, int start) { vector<bool> visited(graph.size(), false); stack<int> s; s.push(start); while (!s.empty()) { int node = s.top(); s.pop(); if (!visited[node]) { visited[node] = true; cout << node << " "; for (int i = graph[node].size() - 1; i >= 0; i--) { int neighbor = graph[node][i]; if (!visited[neighbor]) { s.push(neighbor); } } } } } int main() { int n, m; cin >> n >> m; vector<vector<int>> graph(n, vector<int>()); for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } DFS(graph, 0); return 0; } ``` 广度优先搜索(BFS): ``` #include <iostream> #include <vector> #include <queue> using namespace std; void BFS(vector<vector<int>>& graph, int start) { vector<bool> visited(graph.size(), false); queue<int> q; q.push(start); while (!q.empty()) { int node = q.front(); q.pop(); if (!visited[node]) { visited[node] = true; cout << node << " "; for (int i = 0; i < graph[node].size(); i++) { int neighbor = graph[node][i]; if (!visited[neighbor]) { q.push(neighbor); } } } } } int main() { int n, m; cin >> n >> m; vector<vector<int>> graph(n, vector<int>()); for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } BFS(graph, 0); return 0; } ``` 其中,graph是一个邻接表表示的无向,n表示节点数,m表示边数,start表示遍历的起点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值