IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 广度优先搜索BFS和深度优先搜索DFS查找最短路与最长路(C++实现) -> 正文阅读

[数据结构与算法]广度优先搜索BFS和深度优先搜索DFS查找最短路与最长路(C++实现)

1.广度优先搜索 Breadth First Search(BFS)

1.图例

举个例子,对于这张图:

map
我们想要知道从起点到终点最短需要多少步,采用广度优先搜索的方法:

1.将起点入队。
2.将队首元素向四周可拓展的点入队。如果没有可拓展的点,则说明该点是死路,该元素出队。
3.重复上述步骤,直到到达目标位置或者队列为空。

此过程图示见下图

  1. 所以,我们先将起点(1,1)入队。
  2. 再向它的四周试探:向右有路径,向下有路径,向左无路径,向上无路径。即将(1,2)和(2,1)入队,步数记为1,将这两点标记为已访问。
  3. 再将(1,1)出队。

此时队列内的情况为:
(1,2)点,步数为1
(2,1)点,步数为1

  1. 再对(1,2)点进行四方向拓展,发现(2,2)点可以拓展,则(2,2)点入队,步数记为2,并将(2,2)点标记为已访问。
  2. (1,2)点出队。
  3. 对(2,1)点进行四方向拓展,由于(2,2)点已被访问,无可拓展的点,(2,1)点直接出队。

过程如图所示:

在这里插入图片描述

注:此图为方便理解,标注了更多步数,实际程序5步运行到终点就会停止搜索了。

2.c++实现代码

c++语言实现代码如下:

#include <iostream>
#include <stdio.h>
#include <queue>
using namespace std;

int map[100][100], v[100][100]; //map是地图数组,v是访问数组
struct point
{
    int x;  //行号
    int y;  //列号
    int step;   //步数
};
queue<point> r;                                   //申请队列,用于存储各个点和步数
int dx[4] = {0, -1, 0, 1},dy[4] = {1, 0, -1, 0}; //偏移数组,用于向四方向移动

int main()
{
    //输入
    //n是地图的行数,m是地图的列数,startx,starty是起点坐标,p,q是终点坐标
    int n, m, startx, starty, p, q; 
    printf("请输入地图的行数和列数:");
    scanf("%d%d", &n, &m);
    printf("请依次输入地图各点情况:\n");
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            scanf("%d", &map[i][j]);
    printf("请依次输入起点横纵坐标,终点横纵坐标:");
    scanf("%d%d%d%d", &startx, &starty, &p, &q);

    //BFS
    //对起点start初始化
    point start;
    start.x = startx;
    start.y = starty;
    start.step = 0;

    r.push(start);         //起点入队
    v[startx][starty] = 1; //将起点设置为已访问
    int flag = 0;   //用来标记是否能到达终点,初值为0
    while (!r.empty())
    {
        //使x,y分别为队首元素的行号和列号
        int x = r.front().x, y = r.front().y;
        //到终点的情况
        if (x == p && y == q)
        {
            flag = 1;   //到达终点则flag变量修改为1
            printf("广度搜索结果为:最短路径长度为%d步", r.front().step);
            break;
        }
        //进行四个方向试探
        for (int k = 0; k <= 3; k++)
        {
            //tx,ty是试探的点
            int tx, ty;
            tx = x + dx[k];
            ty = y + dy[k];
            //当试探的点无障碍且未访问时
            if (map[tx][ty] == 1 && v[tx][ty] == 0)
            {
                //将该试探点入队
                //思路:建立一个新的临时结构体变量,复制该试探点的x,y,和步数,然后将临时变量入队,改试探点标记为已访问                point temp;
                temp.x = tx;
                temp.y = ty;
                temp.step = r.front().step + 1;
                r.push(temp);
                v[tx][ty] = 1;
            }
        }
        //拓展完毕的队首元素出队
        r.pop();
    }
    if(flag==0) //没有达到终点的情况
        printf("无解!\n");

    return 0;
}

2.深度优先搜索 Depth First Search(DFS)

1.图例

同样对于这幅图:

在这里插入图片描述
采用广度优先搜索的方法:

对于每一个点,依照顺时针顺序依次对右、下、左、上进行试探,沿着一条路走到底,然后进行回溯到上一个十字路口,试探另一条路……按照这种方法把所有可能性的道路试探完毕。最后取最小的那一个步长。

如下图所示从起点先沿着蓝色路径走到终点,再沿着粉色路径回溯到上一个点、上上个点,走新的岔路进行试探。需要注意的是,每次回溯都要把该点设置为未访问。

在这里插入图片描述
为什么要标记访问的点?
答:防止递归回这个点时候重复调用。

为什么回溯时要取消标记访问过的点?
答:下次通过其他路径去终点的时候可能还会访问到该点。

2.c++实现代码

#include <iostream>
using namespace std;

int p, q, min_step = 9999999; //p,q是终点横纵坐标,最短步长初值为9999999
int map[100][100];                                //1表示空地,2表示障碍物
int v[100][100];                                  //0表示未访问,1表示访问
int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0}; //方向数组

void dfs(int x, int y, int step);

int main()
{
    int m, n, startx, starty;
    cout << "请输入地图行数、列数:\n";
    cin >> m >> n;
    cout << "请输入地图情况:\n";
    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= n; j++)
            cin >> map[i][j];
    cout << "请输入起点横纵坐标,终点横纵坐标:\n";
    cin >> startx >> starty >> p >> q;
    v[startx][starty] = 1;
    dfs(startx, starty, 0);
    if(min_step==9999999)
        cout<<"无法到达终点!";
    else
        cout << "深度优先搜寻的结果为:最短路径为" << min_step;
    return 0;
}

void dfs(int x, int y, int step)
{
    if (x == p && y == q)
    {
        if (step < min_step)
            min_step = step;
        return;
    }
    //顺时针试探
    for (int k = 0; k <= 3; k++)
    {
        int tx, ty;
        tx = x + dx[k];
        ty = y + dy[k];
        if (map[tx][ty] == 1 && v[tx][ty] == 0)
        {
            v[tx][ty] = 1;
            dfs(tx, ty, step + 1);
            v[tx][ty] = 0;
        }
    }
    return;
}

3.BFS与DFS的对比

一般情况下,广度优先搜索相较于深度优先搜索会更加快地接近目标点,而后中止运行,程序的时间复杂度更低。而深度优先搜索则会完全探索出所有能到达目标点的路径才结束,程序的时间复杂度更高
因此,最好使用广度优先搜索寻找最短路(最长路同理),深度优先搜索寻找所有路的种数。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-01 14:44:55  更:2021-08-01 14:47:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/14 8:59:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码