数据结构与算法——DFS与BFS

深度优先搜索(Depth-First Search,简称DFS)是一种用于遍历或搜索树或图的算法。它从一个节点开始,沿着尽可能深的分支进行搜索,直到达到目标或者不能再深入为止,然后回溯到上一个节点,继续搜索其他分支。

DFS通常用于以下几种情况:
1. 检查图是否连通或检查一个节点是否可达。
2. 寻找一条从起点到终点的路径。
3. 解决八皇后问题、图的遍历、拓扑排序等。

DFS可以递归地实现,也可以使用栈来实现非递归形式。


DFS的递归实现

以下是使用C++实现DFS的示例代码:

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

// 假设有一个图的邻接表表示
vector<int> graph[100];

// 用于标记节点是否被访问过
vector<bool> visited(100, false);

// DFS函数
void dfs(int node) {
    // 访问当前节点
    visited[node] = true;
    cout << node << " ";

    // 遍历所有邻接节点
    for (int i = 0; i < graph[node].size(); i++) {
        int adjNode = graph[node][i];
        // 如果邻接节点未被访问,则递归访问它
        if (!visited[adjNode]) {
            dfs(adjNode);
        }
    }
}

int main() {
    // 构建图的邻接表
    graph[0].push_back(1);
    graph[1].push_back(0);
    graph[1].push_back(2);
    graph[2].push_back(1);
    graph[2].push_back(3);
    graph[3].push_back(3);

    // 从节点0开始DFS
    dfs(0);

    return 0;
}

这段代码首先定义了一个邻接表来表示图,然后使用一个布尔向量visited来跟踪每个节点是否已经被访问过。dfs函数递归地访问当前节点的所有未访问的邻接节点。

DFS的非递归实现

非递归的DFS使用栈来模拟递归过程:

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

// 假设有一个图的邻接表表示
vector<int> graph[100];
vector<bool> visited(100, false);

void dfsIterative(int start) {
    stack<int> stack;
    stack.push(start);

    while (!stack.empty()) {
        int node = stack.top();
        stack.pop();

        if (!visited[node]) {
            visited[node] = true;
            cout << node << " ";

            // 将邻接节点压入栈中
            for (int i = graph[node].size() - 1; i >= 0; i--) {
                int adjNode = graph[node][i];
                if (!visited[adjNode]) {
                    stack.push(adjNode);
                }
            }
        }
    }
}

int main() {
    // 构建图的邻接表,与上面的示例相同

    // 从节点0开始迭代DFS
    dfsIterative(0);

    return 0;
}

在这个非递归版本中,我们使用了一个栈来存储待访问的节点。我们首先将起始节点压入栈中,然后在循环中不断从栈中弹出节点进行访问,并将未访问的邻接节点压入栈中。

这两种DFS实现都可以有效地遍历图或树结构,选择哪一种取决于个人偏好和特定问题的需求。


广度优先搜索(Breadth-First Search,简称BFS)是一种遍历或搜索树和图的算法,它从一个节点开始,逐层遍历节点,即先访问所有邻接节点,再访问邻接点的邻接点,直到找到目标节点或遍历完所有节点。

BFS常用于以下场景:
1. 查找最短路径。
2. 查找所有连接节点的路径。
3. 解决社交网络中的朋友推荐问题。

BFS通常使用队列来实现。


 BFS的实现

以下是使用C++实现BFS的示例代码:

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

// 假设有一个图的邻接表表示
vector<int> graph[100];
vector<bool> visited(100, false); // 标记节点是否被访问过

void bfs(int start) {
    queue<int> q;
    q.push(start); // 将起始节点入队
    visited[start] = true; // 标记起始节点为已访问

    while (!q.empty()) {
        int node = q.front(); // 队头元素即为当前节点
        q.pop();

        cout << node << " "; // 访问当前节点

        // 遍历当前节点的所有邻接节点
        for (int i = 0; i < graph[node].size(); i++) {
            int adjNode = graph[node][i];
            if (!visited[adjNode]) {
                q.push(adjNode); // 将未访问的邻接节点入队
                visited[adjNode] = true; // 标记为已访问
            }
        }
    }
}

int main() {
    // 构建图的邻接表
    graph[0].push_back(1);
    graph[1].push_back(0);
    graph[1].push_back(2);
    graph[2].push_back(1);
    graph[2].push_back(3);
    graph[3].push_back(2);

    // 从节点0开始BFS
    bfs(0);

    return 0;
}

这段代码首先定义了一个邻接表来表示图,然后使用一个布尔向量visited来跟踪每个节点是否已经被访问过。bfs函数使用一个队列来按层次遍历节点。

BFS的关键在于使用队列来保持访问顺序,确保先访问的节点先出队,这样可以保证搜索的广度优先性。在实际应用中,BFS可以有效地找到从起点到目标点的最短路径,因为它会先探索所有距离起点一样远的节点。

BFS算法的时间复杂度通常是O(V+E),其中V是顶点数,E是边数。空间复杂度取决于队列的大小,最坏情况下也是O(V)。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值