图的遍历方法——深度优先与广度优先

深度优先搜索(Depth-First-Search)

简介

深度优先搜索算法所遵循的搜索策略是尽可能“深”地搜索一个图。它的基本思想就是:首先访问图中某一起始顶点v,然后由v出发,访问与v邻接且未被访问的任一顶点w1,再访问与w1邻接且未被访问的任一顶点w2,……重复上述过程。当不能再继续向下访问时,依次退回到最近被访问的顶点,若它还有邻接顶点未被访问过,则从该点开始继续上述搜索过程,直到图中所有顶点均被访问过为止。
简单来说,就是这种算法会沿着一个方向一直走,直到不能再走下去位置。当不能继续走的时候则返回上一个位置,按照自己规定的方向顺序循环上述过程。

动态图展示

我定义的方向顺序为↓→↑←。
      《图的遍历方法——深度优先与广度优先》

代码

在写代码的时候,为了防止一个地方被多次走过,一般要用一个数组来标记已经走过的地方,具体代码如下。

/* ######## #*****## #*###*## #***#**# #*#*#*## #*#*#**# #*#****# ######## #代表墙,*代表可以走的地方 */
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
char DT[9][9];
int vis[9][9],xy[4][2]={1,0,0,1,-1,0,0,-1};
int n;
int flag = 0;
int place(int x,int y) // 判断此位置是否可走
{
    if (x>=0&&x<n&&y>=0&&y<n&&DT[x][y]=='*'&&!vis[x][y])
        return 1;
    return 0;
}
void DFS(int a,int b)
{
    if (a==n-2&&b==n-2)
        flag = 1;
    if (flag == 1)  // 当找到一条路的时候结束搜索
        return ;
    for (int i=0;i<4;i++)
    {
        int x=a+xy[i][0];
        int y=b+xy[i][1];
        if (place(x,y))
        {
            vis[x][y]=1;
            DFS(x,y);
        }
    }
}
int main()  // 地图的起点为(1,1)终点为(n-2,n-2)
{
    cin>>n;  //定义地图为n*n
    for (int i=0;i<n;i++) // 输入地图
        for (int j=0;j<n;j++)
            cin>>DT[i][j];
    memset(vis,0,sizeof(vis));
    DFS(1,1);
    if (flag==1)
        cout<<"Yes."<<endl;
    else
        cout<<"No."<<endl;
    return 0;
}

这只是一个简单的模板,在遇到不同的问题时,要根据题意进行相应的改变。

广度优先搜索(Breadth-First-Search)

简介

从V0出发,访问V0的各个未曾访问的邻接点W1,W2,…,Wk;然后,依次从W1,W2,…,Wk出发访问各自未被访问的邻接点;重复步骤,直到全部顶点都被访问为止。简单来说,广度优先搜索会将此状态下所有能走的地方一次性走完,然后再从下一层开始,重复这个步骤,直到走到目的地或者将整个地图遍历完。

动态图展示

      《图的遍历方法——深度优先与广度优先》

代码

广度优先遍历要用到队列来实现,在有些情况下还要用到优先队列。

/* ######## #*****## #*###*## #***#**# #*#*#*## #*#*#**# #*#****# ######## #代表墙,*代表可以走的地方 */

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
char DT[9][9];
int vis[9][9],n;
int xy[4][2]={1,0,0,1,-1,0,0,-1};
struct node
{
    int x,y;  // 坐标
    int pre;  // 步数
};
int place(int x,int y) // 判断此位置是否可走
{
    if (x>=0&&x<n&&y>=0&&y<n&&DT[x][y]=='*'&&!vis[x][y])
        return 1;
    return 0;
}
int BFS(int x,int y)
{
    memset(vis,0,sizeof(vis));
    queue<node>it;  // 定义队列
    node o,e;
    e.x=x;
    e.y=y;
    e.pre=0;
    it.push(e);   
    vis[e.x][e.y]=1;
    while (!it.empty())
    {
        e=it.front();
        it.pop();
        if (e.x==n-2&&e.y==n-2)  // 到达终点,返回所用的步数
            return e.pre;
        for (int i=0;i<4;i++)
        {
            o.x=e.x+xy[i][0];
            o.y=e.y+xy[i][1];
            o.pre=e.pre+1;
            if (place(o.x,o.y))
            {
                it.push(o);
                vis[o.x][o.y]=1;
            }
        }
    }
    return -1;  // 不能到达终点返回-1
}
int main()
{
    cin>>n;  //定义地图为n*n
    for (int i=0;i<n;i++) // 输入地图
        for (int j=0;j<n;j++)
            cin>>DT[i][j];
    int ans=BFS(1,1);
    if (ans==-1)
        cout<<"Can't get to the finish line."<<endl;
    else
        cout<<ans<<endl;
    return 0;
}

在某些情况下,每一步所消耗的单位可能不一样,这个时候就要用到优先队列了。
优先队列可以将队列中的元素按照某一元素进行排列。

优先队列定义方法:

#include <include queue>
struct node
{
    int x, y, pre;
    friend bool operator < (node a,node b)
    {
        return a.pre>b.pre;
    }
};
priority_queue<node>it;

两种方法的区别

广度优先遍历与深度优先遍历的区别在于:广度优先遍历是以层为顺序,将某一层上的所有节点都搜索到了之后才向下一层搜索;而深度优先遍历是将某一条枝桠上的所有节点都搜索到了之后,才转向搜索另一条枝桠上的所有节点。

深度优先遍历从某个顶点出发,首先访问这个顶点,然后找出刚访问这个结点的第一个未被访问的邻结点,然后再以此邻结点为顶点,继续找它的下一个新的顶点进行访问,重复此步骤,直到所有结点都被访问完为止。

广度优先遍历从某个顶点出发,首先访问这个顶点,然后找出这个结点的所有未被访问的邻接点,访问完后再访问这些结点中第一个邻接点的所有结点,重复此方法,直到所有结点都被访问完为止。

两种方法最大的区别在于前者从顶点的第一个邻接点一直访问下去再访问顶点的第二个邻接点;后者从顶点开始访问该顶点的所有邻接点再依次向下,一层一层的访问。

    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/BestFM/article/details/80502442
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞