算法06-搜索算法-广度优先搜索

news2024/7/6 20:15:59

文章目录

    • 参考:
    • 总结
    • 大纲要求
    • 搜索算法-广度优先搜索
      • 迷宫问题
        • 问题
        • 迷宫的存储
        • 迷宫的移动
        • 搜索方式
        • 代码实现
      • 图的广度优先遍历
        • 题目描述
        • 用邻接矩阵表示图
    • 搜索算法-广度优先搜索

在这里插入图片描述

参考:

【算法设计】用C++类和队列实现图搜索的广度优先遍历算法

C/C++ 之 广度优先搜索

算法讲解之广度优先搜索

总结

本系列为C++算法学习系列,会介绍 算法概念与描述,入门算法,基础算法,数值处理算法,排序算法,搜索算法,图论算法, 动态规划等相关内容。本文为搜索算法部分。

大纲要求

【 5 】深度优先搜索
【 5 】广度优先搜索

搜索算法-广度优先搜索

在这里插入图片描述

广度优先搜索(Breadth-First Search),又称作宽度优先搜索。BFS是一种完备策略,即只要问题有解,它就一定可以找到解。并且,广度优先搜索找到的解,还一定是路径最短的解。但是它盲目性较大,尤其是当目标节点距初始节点较远时,将产生许多无用的节点,因此其搜索效率较低。一般只有需求最优解的时候会用BFS

广度优先搜索算法(又称宽度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。

广度优先算法的核心思想是:从初始节点开始,应用算符生成第一层节点,检查目标节点是否在这些后继节点中,若没有,再用产生式规则将所有第一层的节点逐一扩展,得到第二层节点,并逐一检查第二层节点中是否包含目标节点。若没有,再用算符逐一扩展第二层的所有节点……,如此依次扩展,检查下去,直到发现目标节点为止。即

⒈从图中的某一顶点V0开始,先访问V0;
⒉访问所有与V0相邻接的顶点V1,V2,…,Vt;
⒊依次访问与V1,V2,…,Vt相邻接的所有未曾访问过的顶点;
⒋循此以往,直至所有的顶点都被访问过为止。
这种搜索的次序体现沿层次向横向扩展的趋势,所以称之为广度优先搜索。

int Bfs()
{
初始化,初始状态存入队列;
队列首指针head=0; 尾指针tail=1do
 {
    指针head后移一位,指向待扩展结点;
    for (int i=1;i<=max;++i)                  //max为产生子结点的规则数
     { 
      if (子结点符合条件)
         {
           tail指针增1,把新结点存入列尾;
           if (新结点与原已产生结点重复) 删去该结点(取消入队,tail减1;
   else
       if (新结点是目标结点) 输出并退出;
              }
         }
}while(head<tail);                       //队列为空
}

迷宫问题

问题

在这里插入图片描述

现在有一个4*4的迷宫,李雷在迷宫的左上角,迷宫出口在右下角,李雷体力有限,他希望尽快走出迷宫,请你告诉李雷最少需要走多少步(每个格子不能重复走动)。

在这里插入图片描述

我们可以按照这样的思路去找:
1.从起点出发,检查第1步可以到达的所有点,判断是否为终点。
2.依次从第1步到达的点出发,检查判断第2步可以到达的点是否为终点。
3.依次从第2步到达的点出发,检查判断第3步可以到达的点是否为终点。
4.依次从第3步到达的点出发,检查判断第4步可以到达的点是否为终点。
5.依次从第4步到达的点出发,检查判断第5步可以到达的点是否为终点。
6.找到终点,程序结束,步数为5。

迷宫的存储

在这里插入图片描述

迷宫的移动

在这里插入图片描述

搜索方式

1.我们需要使用队列(que)来实现,用一个结构体表示每次找到的点的坐标信息以及步数(x,y,cnt)。
2将起点入队。
在这里插入图片描述3.取出队首元素,队首后移(head++) ,将队首元素上下左右的四个点依次入队(步数cnt要+1),同时判断是否到达终点,若到达终点则终止程序。
4.重复步骤3,直到找到终点或者队列为空(即head>tail)
在这里插入图片描述

代码实现

#include<iostream>
using namespace std;

struct wz
{
    int x,y;//坐标
    int cnt;//步数

} que[1000],front,a;//front 用来存每次取出的队首元素,a存起点信息
int maze[5][5];// 迷宫信息
int used[5][5];//已经使用 一般为book
int fx[4][2] = {
{0,-1},//下
{0,1},//上
{-1,0},//左
{1,0}//右
};
int head=1;//队列的头
int tail=1;//队列的尾
int sx=1,sy=1;// sx起点 sy终点
int ex=3,ey=4;//终点的坐标
int flag=0;
void bfs(wz a);// 广度优先函数
int maze_data[5][5]={
{0,0,0,0,0},
{0,1,1,1,1},
{0,1,0,1,1},
{0,1,1,1,1},
{0,1,1,1,1}
};
int main()
{
    for(int i=1;i<=4;i++)
    {
        for(int j=1;j<=4;j++)
        {
            maze[i][j]=maze_data[i][j];
//            cout<<maze[i][j];
//            cin>>maze[i][j];//填充迷宫

        }
//        cout<<endl;
    }
    a.x=sx;//存起点信息
    a.y=sy;//存起点信息
    a.cnt=0;//初始步数为0
    bfs(a);//从a点开始搜索
    cout<<" head"<<head<<" tail:"<<tail<<endl;
    cout<<que[tail].cnt;//输出尾节点的步数
    return 0;

}

void bfs(wz a)
{
    que[head]=a;//起点入队
    used[a.x][a.y]=1;//起点被使用
    cout<<" head:"<<head<<" tail:"<<tail<<endl;
    cout<<" que[head]:"<<que[head].x<<" "<<que[head].y <<" "<<que[head].cnt<<"used[a.x][a.y]:"<<used[a.x][a.y]<<endl;
    while(head<=tail)//当head<tail表示队列不为空
    {

        cout<<"while循环内: head:"<<head<<"tail:"<<tail<<endl;
        front = que[head];//取出队首
        head++;//队首出队
        for(int i=0;i<4;i++)//搜索队列当前节点的四个方向的点
        {
            int nx=front.x+fx[i][0];//搜索的nx坐标
            int ny=front.y+fx[i][1];//搜索的ny坐标  下一个节点的坐标
            // 下一个节点坐标不超出迷宫范围,未被走过,且不是障碍
            if(nx>=1 && nx<=4 && ny>=1 &&ny<=4 && !used[nx][ny] && maze[nx][ny])
            {
                tail++;//把tail队尾后移,表示添加节点
                used[nx][ny]=1;//标记走过
                que[tail].x=nx;
                que[tail].y=ny;
                // 等价与que[++tail].x=nx
                que[tail].cnt=front.cnt+1;//步数+1
                cout<<"for循环 if内: nx:"<<nx<<"ny:"<<ny<<"cnt:"<<front.cnt+1<<endl;
            }
            if(nx==ex && ny==ey)
            {
                head=tail+1;//推出while循环
                break;//推出for循环
            }


        }
    }

}

在这里插入图片描述

图的广度优先遍历

题目描述

在这里插入图片描述
使用广度优先遍历算法输出访问结点的顺序,结果为0、1、2、4、5、8、9、3、6、7、10

用邻接矩阵表示图

在这里插入图片描述

按照案例给出的图,我简化成了这个邻接矩阵,画法就是,两个结点之间相连设置为T,不相连设置为F,规定结点自身与自身不相连,当然对T和F要有声明,例如 const bool T =true,F=false;这样T就代表通路,F就代表断路了

#include<iostream>
using namespace std;

const int n=11;// 结点个数
const int SIZE=10;

class queue
{
private:
    int buffer[SIZE];//队列长度
    int rear;//rear指向队尾
    int head;//head 指向队列前一格
    // 使得rear和head的指向向下进行
    // 对10取余 得到个位数,
    int update(int value)
    {
        return (value+1)%SIZE;
    }
public:
    // 无参构造,利用初始化列表给head和rear的初始化为0
    queue():head(0),rear(0){}
    // 判断队列是否为空
    bool queueNull(){return rear == head;}
    // 队满的判断 让rear和head的下标重置为0
    bool queueMax(){return update(rear)==head;}
    bool queueAdd(int E)
    {
        // 如果队满了就不添加
        if(queueMax()) return false;
        rear = update(rear);//更新队尾的指针,队尾指针+1
        buffer[rear] = E; //把数据E插入到队列的队尾中
        return true;
    }
    //区队首元素的方法
    bool getFirstQueue(int& E)
    {
        //如果队空了,返回
        if(queueNull()) return false;//
        head = update(head);//更新队首指针
        E = buffer[head];//取出队首
        return true;

    }

};

const bool F = false, T = true;
bool nextClose[n][n] = {
    {F,T,T,F,F,F,F,F,F,F,F},
    {T,F,F,F,T,T,F,F,F,F,F},
    {T,F,F,F,F,F,F,F,T,T,F},
    {F,F,F,F,T,F,F,F,F,F,F},
    {F,T,F,T,F,F,T,F,F,F,F},
    {F,T,F,F,F,F,F,T,F,F,T},
    {F,F,F,F,T,F,F,F,F,F,F},
    {F,F,F,F,F,T,F,F,F,F,F},
    {F,F,T,F,F,F,F,F,F,F,F},
    {F,F,T,F,F,F,F,F,F,F,F},
    {F,F,F,F,F,T,F,F,F,F,F}
};

bool flag[n];
//假设begin为0结点
void BreadthFirstSearch(int begin)
{
    for(int i=0;i<n;i++)
    {
        // 先把标志位flag数组全设置为false
      flag[i]=false;
    }

    queue que; //创建队列对象
    que.queueAdd(begin); // 把元素添加到队列中的第2个格子
    flag[begin] = true;//把标记为设置为true

    int node;
    while(!que.queueNull())
    {
        que.getFirstQueue(node);
        cout<<node<<",";
        for(int i=0;i<n;i++)
        {
            if(nextClose[i]&&!flag[i])
            {
                que.queueAdd(i);
                flag[i]=true;
            }
        }

    }

}


int main()
{
    BreadthFirstSearch(0);
    cout<<"hello world"<<endl;
}

搜索算法-广度优先搜索

在深度优先搜索算法中,是深度越大的结点越先得到扩展。如果在搜索中把算法改为按结点的层次进行搜索,本层的结点没有搜索处理完时,不能对下层结点进行处理,即深度越小的结点越先得到扩展,也就是说先产生的结点先得以扩展处理,这种搜索算法称为广度优先搜索法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/757776.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

梯度下降(Gradient Descent)

基本思想 梯度下降是一个用来求函数最小值的算法&#xff0c;本次&#xff0c;我们将使用梯度下降算法来求出代价函数的最小值。 梯度下降背后的思想是&#xff1a;开始时我们随机选择一个参数的组合&#xff0c;计算代价函数&#xff0c;然后我们寻找下一个能让代价函数值下降…

Linux:squid透明代理

在传统代理上进行修改并添加网卡 这次不使用手动代理&#xff0c;而是把网关搞成代理 在下面这个链接里的文章实验下进行修改 Linux&#xff1a;squid传统代理_鲍海超-GNUBHCkalitarro的博客-CSDN博客 完成以后不用再win10上去配置&#xff0c;代理的那一步&#xff0c;然后…

Python(十二)常见的数据类型

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

TabLayout+ViewPager实现滚动页面

目录 一、TabLayout介绍 二、TabLayout的常用属性和方法 常用属性&#xff1a; 常用方法&#xff1a; 三、适配器介绍 &#xff08;一&#xff09;、PagerAdapter介绍&#xff1a; &#xff08;二&#xff09;、FragmentPagerAdapter介绍&#xff1a; &#xff08;三&am…

习题 1.26

我们先来看看题目要求&#xff0c;题目住说将 square 调用换成了&#xff08;* x x),结果导致执行时间变慢。 根据以前学过的内容&#xff0c;我们知道 在做显示乘法的时候&#xff0c;是直接进行计算的&#xff0c;而在做函数调用的时候&#xff0c;是先进行表达式展开的&…

【MySQL】常见函数使用(二)

&#x1f697;MySQL学习第二站~ &#x1f6a9;本文已收录至专栏&#xff1a;数据库学习之旅 ❤️文末附全文思维导图&#xff0c;感谢各位点赞收藏支持~ 就如同许多编程语言中的API一样&#xff0c;MySQL中的函数同样是官方给我们封装好的&#xff0c;可以直接调用的一段代码。…

ZooKeeper ZAB

文章首发地址 在接收到一个写请求操作后&#xff0c;追随者会将请求转发给群首&#xff0c;群首将探索性地执行该请求&#xff0c;并将执行结果以事务的方式对状态更新进行广播。一个事务中包含服务器需要执行变更的确切操作&#xff0c;当事务提交时&#xff0c;服务器就会将这…

dp算法篇Day7

"抱紧你的我&#xff0c;比国王富有~" 31、最长定差子序列 (1) 题目解析 从题目来看还是很容易理解的&#xff0c;就是找寻数组中构成差值相等的子序列。 (2) 算法原理 class Solution { public:int longestSubsequence(vector<int>& arr, int difference…

多模态系列论文--ALBEF 详细解析

ALBEF来自于Align before Fuse&#xff0c;作者团队全自来自于Salesforce Research。 论文地址&#xff1a;Align before Fuse: Vision and Language Representation Learning with Momentum Distillation 论文代码&#xff1a;ALBEF 1 摘要 最近图像文本的大规模的特征学习非…

AI Chat 设计模式:7. 单例模式

本文是该系列的第七篇&#xff0c;采用问答式的方式展开&#xff0c;问题由我提出&#xff0c;答案由 Chat AI 作出&#xff0c;灰色背景的文字则主要是我的旁白和思考。 问题列表 Q.1 简单介绍一下单例模式A.1Q.2 详细说说饿汉式&#xff0c;并使用 c 举例A.2Q.3 好&#xff…

【半监督医学图像分割 2022 IJCAI】UGPCL

文章目录 【半监督医学图像分割 2022 IJCAI】UGPCL摘要1. 介绍2. 相关工作2.1 半监督医学图像分割2.2 对比学习2.3 不确定度估计 3. 方法3.1 解码器间的一致性学习3.2 不确定性引导的对比学习3.3 等变对比损失 4. 实验4.1 实验设置4.2 定量实验4.3 消融实验 5. 结论 【半监督医…

引爆用户流量,打造热门小红书创业项目

引爆用户流量&#xff0c;打造热门小红书创业项目 在当今互联网时代&#xff0c;创业者们不断寻求新的商机和盈利模式。而小红书作为一个以分享购物心得、美妆、旅行等内容为主的社交平台&#xff0c;成为了众多创业者关注的焦点。如何通过小红书引爆用户流量&#xff0c;并打造…

【框架篇】使用注解存储对象

使用注解存储对象 之前我们存储Bean时&#xff0c;需要在spring-config 中添加一行 bean注册内容才行&#xff0c;如下图所示&#xff1a; 问题引入&#xff1a;如果想在Spring 中能够更简单的进行对象的存储和读取&#xff0c;该怎么办呢&#xff1f; 问题解答&#xff1a;实…

Python应用实例(一)外星人入侵(十)

外星人入侵&#xff08;十&#xff09; 1.记分1.1 显示得分1.2 创建记分牌1.3 在外星人被消灭时更新得分1.4 重置得分1.5 将消灭的每个外星人都计入得分1.6 提高分数1.7 舍入得分1.8 最高得分1.9 显示等级1.10 显示余下的飞船数 1.记分 下面来实现一个记分系统&#xff0c;以实…

动态规划01背包之1049 最后一块石头的重量 II(第11道)

题目&#xff1a; 有一堆石头&#xff0c;用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合&#xff0c;从中选出任意两块石头&#xff0c;然后将它们一起粉碎。假设石头的重量分别为 x 和 y&#xff0c;且 。那么粉碎的可能结果如下&#xff1a; …

4029: 网格行走

题目内容 在一个 n n n \times n nn 的网格上行走&#xff0c;从 ( 1 , 1 ) (1, 1) (1,1) 走到 ( n , n ) (n, n) (n,n)。每次只能向下走一步或向右走一步。 每个点 ( i , j ) (i, j) (i,j) 有权值 a i , j a_{i, j} ai,j​&#xff0c;给定一个数 x x x&#xff0c;求…

电机驱动系列(1)--例程下载演示

电机驱动系列&#xff08;1&#xff09; 使用设备连线实操感想 使用设备 硬件&#xff1a;野火骄阳板–STM32F407IGT6&#xff0c;野火无刷电机驱动板&#xff0c;PMSM电机软件&#xff1a;MCSDK&#xff0c;STM32CubeMX&#xff0c;Keil5软件安装注意事项&#xff1a;MCSDK-F…

SOF-SLAM论文翻译

SOF-SLAM:面向动态环境的语义可视化SLAM 摘要-同时定位与绘图(SLAM)在计算机视觉和机器人领域中占有重要地位。为了便于分析&#xff0c;传统的SLAM框架采用了强静态世界假设。如何应对动态环境是一个非常重要的问题&#xff0c;越来越受到人们的关注。现有的动态场景SLAM系统…

MySQL不适合创建索引的7种情况

1. 在where中使用不到的字段&#xff0c;不要设置索引 WHERE条件&#xff08;包括order by &#xff0c;group by&#xff09; 2. 数据量小的表最好不要使用索引 表记录太少&#xff0c;比如少于1000个&#xff0c;创建索引会先查索引&#xff0c;再回表&#xff0c;查询花费…

虚拟机安装及使用

无论下载什么软件&#xff0c;最好都要单独设置个文件夹 文章目录 VMware下载CentOS下载Xshell 7下载WinSCP下载linux命令 VMware下载 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; VMware Workstation Pro安装 一直傻瓜式安装 可以上网找许可证秘钥 …