bfs和dfs

本文详细介绍了深度优先搜索(DFS)和广度优先搜索(BFS)这两种图遍历算法的特点和实现方式。DFS通过栈进行操作,沿着一条路径直到无法继续时回溯;BFS则使用队列,按层次逐层访问节点。同时提供了C++代码示例,加深理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

bfs和dfs

特点与区别
深度优先搜索和广度优先搜索都是用来遍历一个图的,两种遍历方法的主要特点是

  • 深度优先:不撞南墙不回头
  • 广度优先:向外扩散

现在可能听起来很让人疑惑,接下来我们逐个来析:

深度优先搜索

深度优先搜索(Depth First Search):的主要思路是沿着一条路径一直走,直到走不动的时候再回头。什么时候叫走不动的时候呢,当访问到一个图中一个结点时,该结点已经没有任何的邻接的且未访问的结点时,此时可形象地称为走不动了,撞了南墙了。
深度优先搜索的实现往往和一种数据结构——联系在一起,具体思路如下:

  1. 设定一个遍历的起点,并将其入栈;
  2. 访问并弹出栈顶结点,将栈顶结点的邻接的且未访问的结点入栈;
  3. 重复步骤2,直到栈为空;

C++代码实现如下(图以邻接矩阵为例,以结点的序号来表示结点)

void dfs(int start)
{
    stack<int>search_sta;
    vector<bool>visited(size,false);
    int temp_node;
    search_sta.push(start);     //起点入栈
    visited.push_back(start);   //标为已知
    while(!search_sta.empty())
    {
        temp_node = search_sta.top();   //访问栈顶元素
        search_sta.pop();               //栈顶元素出栈
        for(int i = 0; i < size; i++)
        {
            if(edges[temp_node][i]&&visited[i]==false)
            {
                //将未访问的邻接点入栈并标为已访问
                search_sta.push(i);
                visited[i]=true;
            }
        }
    }
}

同样的,我们也可以用递归的方式来实现dfs,事实上递归也是一种栈,代码如下:

void dfs_recursion(int start)
{
    static vector<bool>visited(size,false);
    visited[start]=true;
    for(int i = 0; i < size; i++)
    {
        if(visited[i]==false&&edges[start][i])
        {
            dfs_recursion(i);
        }
    }
}

广度优先搜索

广度优先搜索(Breadth First Search)的主要思路是从起点开始,访问其所有邻接点,再依次访问这每个邻接点的所有邻接点(好像有点绕)。与深度优先搜索所不同的是,广度优先搜索对于每个结点和它的邻接点都尝试去访问。从直观上来看,bfs是一层一层的,第一层访问最近一圈的结点(假设是无权图),而后层数随着圈不断向外扩展。
广度优先搜索的实现往往和另一种数据结构——队列有关,具体思路如下:

  1. 设定一个遍历的起点,将起点入队;
  2. 访问队头结点并将其出队,将队头结点的所有邻接且未访问结点入队;
  3. 重复步骤2直到队为空;

C++实现代码如下(图用邻接表实现,用结点的序号代表结点):

void bfs(int start)
{
    queue<int>search_que;
    vector<bool>visited(size,false);
    int temp_node;
    search_que.push(start);
    visited[start]=true;
    while(!search_que.empty())
    {
        temp_node = search_que.front();     //访问队头元素
        search_que.pop();                   //队头元素出队
        for(auto t : edges[temp_node])  //map<int,set<int>>edges
        {
            if(visited[t]==false)
            {   
                //将未访问的邻接点入队并标为已知
                search_que.push(t);     
                visited[t] = true;       
            }
        }
    }
}

在C++中,个人习惯用关联容器来实现图的邻接表,例如对于无权图,可用
map<node,set<node>>edges
来表示,以结点为键,以该结点的所有邻接点的集合为值。
而对于有权图,则可用
map<node,map<node,weight>>edges
来表示,例如edges[node1][node2]即为连接node1和node2两结点的边的权值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值