数据结构学习——栈的应用:迷宫问题

2023-11-12

简介

基于栈的迷宫问题本质上是深度优先遍历,从起点开始深度优先搜索,遇到碰壁的情况时,根据栈的特性,可以“回溯”到之前走过的路,并继续搜索未搜索的方向。

具体实现

我使用的ide是qt,它里面的一些图形库有助于我更加直观地理解深度优先搜索的过程。

我创建了迷宫类maze:

class maze
{
    friend class widget;
protected:
    int scale;//边长
    int** data;
public:
    maze(int s = 10):scale(s)
    {
        data = new int*[scale];
        for(int i = 0;i <= scale - 1;++i)
        {
            data[i] = new int [scale];
        }
    }
    ~maze()
    {
        for(int i = 0;i <= scale - 1;++i)
        {
            delete [] data[i];
        }
        delete [] data;
    }
    int getScale() const{return scale;}
    int** getData() const{return data;}//to be changed
    void createMaze(const QString& cmd);//根据用户输入创建迷宫
    void print() const;//在控制台输出
    void findPath(QWidget* parent);//寻路,并在窗口中显示出来

};

迷宫的信息用一个scale*scale的二维数组存储,数组的值对应如下:

0:墙壁;1:空气;2:探测到的路;3:最终寻路的结果;4:无法走通的路

本文对应的迷宫如下,起点在左上角,终点在右下角。

寻路函数findPath传入参数QWidget* parent,方便对窗口进行图形化的绘制。

void maze::findPath(QWidget *parent)
{
    struct dirPoint//数据包,存储一个位置和其访问方向的信息
    {
        int x;
        int y;
        int dir;
        dirPoint(int xx,int yy,int d = 0):x(xx),y(yy),dir(d){}
    };
    stack<dirPoint> st;
    dirPoint curPoint(0,0),lastPoint(0,0);//当前位置信息和上一个位置信息
    bool isExplored;//标记一次探测是否成功
    st.push(dirPoint(0,0));
    while(!st.empty())
    {
        Sleep(20);
        isExplored = false;
        curPoint = st.top();
        st.pop();
        if(curPoint.dir == 4)//全部方向都已经被探索过
        {
            data[curPoint.x][curPoint.y] = 4;//设置为“失败点”
            parent->repaint();
            continue;
        }
        switch(curPoint.dir)
        {
        case 0:if(curPoint.x >= 1 && data[curPoint.x -1][curPoint.y] == 1)
                {
                    lastPoint = curPoint;
                    --curPoint.x;
                    isExplored = true;
                }break;//up
        case 1:if(curPoint.x <= scale - 2 && data[curPoint.x + 1][curPoint.y] == 1)
                {
                    lastPoint = curPoint;
                    ++curPoint.x;
                    isExplored = true;
                }break;//down
        case 2:if(curPoint.y >= 1 && data[curPoint.x][curPoint.y - 1] == 1)
                {
                    lastPoint = curPoint;
                    --curPoint.y;
                    isExplored = true;
                }break;//left
        case 3:if(curPoint.y <= scale - 2 && data[curPoint.x][curPoint.y + 1] == 1)
                {
                    lastPoint = curPoint;
                    ++curPoint.y;
                    isExplored = true;
                }//right
        default:break;
        }
        if(isExplored)
        {
            data[curPoint.x][curPoint.y] = 2;
            parent->repaint();
            ++lastPoint.dir;
            st.push(lastPoint);
            curPoint.dir = 0;
            st.push(curPoint);
        }
        else
        {
            ++curPoint.dir;
            st.push(curPoint);
        }
        if(curPoint.x == scale - 1 && curPoint.y == scale - 1)
        {
            break;
        }
    }
    while(!st.empty())
    {
        curPoint = st.top();
        st.pop();
        data[curPoint.x][curPoint.y] = 3;
        parent->repaint();
        Sleep(20);
    }

}

在函数findPath内,我写了一个包裹类,dirPoint,它有三个成员,x(行坐标),y(列坐标),dir(下一步要搜索的方向:0:上,1:下,2:左,3:右),用一个该类的栈进行深度优先搜索。同时,该函数使用bool型局部变量isExplored判断是否探路成功,该布尔值在每一次循环开始都被置为false。设置两个QPoint类的对象lastPoint和curPoint存储当前位置和上一位置。

初始时先将起点进栈,并将dir设为0,表示下一步要搜索的方向为上方。

显然上方此路不通,isExplored仍为false,于是将dir++,表示下一次搜索下方,并将该点进栈。

尝试了下、左都不行后,尝试向右行进,探路成功,isExplored变为true,并将当前位置赋值给lastPoint,同时dir++,curPoint更新为新探测到的位置,并将dir设为0(全新的点,四个方向都没有探测)。出switch语句后,由于isExplored变为true,依次将lastPoint和curPoint进栈。

由于规定路径不能重叠,已经走过的路会被视为“墙壁”,不允许返回探测,路径的回溯只依赖于栈的特点。

当弹出的一个点dir == 4时,表示四个方向已经探测完毕,此路必然不通,则continue,进入下一轮循环时,弹出的点必然是路径的上一个点,如果还有别的方向,则尝试该方向,如果仍然dir == 4,表示这个点也走进了死胡同。于是,当进入死胡同时,利用栈的“回溯”可以逐个退出死胡同。

如果起点重点连通,必然能够找到从起点到终点的路径,此时,依次出栈,得到的就是从终点到起点的逆向路径。

如图所示,深红色为路径,浅红色为探测失败的死胡同。

值得注意的是,使用栈实现的迷宫路径不是最短路径。 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构学习——栈的应用:迷宫问题 的相关文章

随机推荐

  • 宝来车联网显示服务器开小差,思域请靠边站,比亚迪秦Pro在此!还有导航路况信息显示、车联网 快来瞧瞧!...

    由于各地政策的不同 燃油车和新能源车在各地的发展情况也有所不同 接下来要讲得两辆汽油车还不错 分别是秦Pro和宝来 让我们来一起了解一下吧 车型 比亚迪秦Pro 2018款 1 5TI 自动智联锋尚型 国V 指导价 9 98万元 2020
  • 统计二叉树结点个数(C语言)

    函数接口定义 int NodeCount BiTree T T是二叉树树根指针 函数NodeCount返回二叉树中结点个数 若树为空 返回0 裁判测试程序样例 include
  • matlab双因素模型,matlab双因素方差分析

    在MATLAB中求解 源程序 a 76 67 81 56 51 82 69 96 59 70 68 59 上页 下页 返回 表4 9 双因素试验的方差分析表 方差来源 平方和 自由度 因素 方差分析用于两个或者两个以上因素样本均值的检验问
  • 【行为识别】TSN/TRN/TSM/SlowFast/Non-local

    前言 记录视频理解领域的几篇文章吧 由于每篇值得记录的东西不多 所以合在一起 关于开源框架 有港中文多媒体实验室的MMAction 有设备的就尽量多跑跑模型吧 视频相对于静态图像多了时间维度 静态图像的分类 检测 分割做得相对完善了 视频方
  • 2015中国数据库技术大会简介

    作为国内数据库与大数据领域最大规模的技术盛宴 2015第六届中国数据库技术大会 DTCC 即将于2015年4月16日 18日在北京新云南皇冠假日酒店震撼登场 大会以 大数据技术交流和价值发现 为主题 云集了国内外顶尖专家 共同探讨MySQL
  • Vue项目打包部署到Tomcat

    废话不多说 直接进入正题 一 通常在开发环境下请求后台接口会用到反向代理 而在生产环境中反向代理是不生效的 那么为了避免部署在服务器上时需要一个一个更改接口地址这种麻烦费时的操作 更改配置文件去自动切换接口地址 开发环境 在config文件
  • 关于使用QTcpSocket的一些总结

    QTcpSocket类的方法connectToHost会泄露内存 即使把调用这个方法的QTcpSocket实例delete掉 内存也不会释放 反复connectToHost会导致段错误 十分危险 必须控制connectToHost的使用次数
  • 10.文件操作

    CSAPP笔记 1 shell程序设计 2 内存管理 3 链接库 4 文件操作 5 多进程 6 多线程 7 网络编程 8 makefile 9 调试技巧与调试工具 文章目录 CSAPP笔记 前言 一 基础知识 1 文件复制 2 扫描目录 3
  • SpringBoot 2 -SpringBoot入门

    SpringBoot 2 SpringBoot入门 1 简介 2 第一个SpringBoot程序 3 升级 4 响应封装类配置 1 简介 springboot是什么 Spring Boot它本身并不提供Spring框架的核心特性以及扩展功能
  • 安装mysql5.7笔记

    1 查看系统中是否自带安装mysql yum list installed grep mysql 2 删除系统自带的mysql及其依赖 防止冲突 yum y remove mysql libs x86 64 3 安装wget命令 yum i
  • 计算机网络的体系结构--学习计算机网络的重中之重

    一 计算机网络体系结构的设计 1 为什么需要计算机网络体系结构 连接在网络上的两台计算机需要互相传送文件 a 必须有一条传送数据的通路 b 发起通信的计算机要将数据通信的通路激活 激活就是发出一些信令 保证要传送的计算机数据能在这条通路上正
  • 图的m着色问题(回溯法-满m叉树)

    span style font family none background color rgb 255 255 255 1 问题描述 span 给定无向连通图G和m种不同的颜色 用这些颜色为图G的所有顶点着色 每个顶点着一种颜色 每条边的
  • 时域采样,频域为什么周期延拓了

    频域周期延拓只是表面现象 其实质是不同的信号采样后的像可能相同 不可区分 如果硬要做实验 还是要有一定的编程基础 起码要整一个声音出来 让你听一听 可是你要重复这一实验可能又太难了 所以我还是讲一讲简单的数学原理 并用简单的三角函数及程序验
  • Linux系统同时安装MySQL5.7和MySQL8.0

    本文是在一台Centos7虚拟机上面同时安装mysql5 7和mysql8 0的步骤 记录一下 方便后续回顾 这篇文章之后会接着学习搭建两台虚拟机一主一从的架构 其中配置的文件名称 目录 端口号 IP地址要根据自己电脑的实际情况进行更改 m
  • Ubuntu 22.04上安装Docker的完整过程

    更新系统软件包 sudo apt update 安装所需的依赖包 以允许APT使用HTTPS sudo apt install apt transport https ca certificates curl software proper
  • Docker构建tomcat无法用startup.sh启动,无法输出catalina.out

    最近部署测试环境 想尝试一下docker 毕竟技术人不能落伍 So 我先学习了一下docker的简单使用 很多东西都是实践出真知 没必要看书找教程 大概看一下能干就可以了 菜鸟教程地址Docker 教程 菜鸟教程 初学者可以了解一下 下面进
  • 编程变量命名的一些技巧

    最近做项目仿真时 在编程的时候发现自己对变量的命名比较混乱 没有统一的规则 故搜集了一些资料对变量命名的技巧和原则有所了解和总结 总的来说 就是英文字母大小写 数字 下划线 按照一定的规则搭配 自己比较喜欢的是帕斯卡 pascal 命名法和
  • stm32f103 TIM2定时器4路PWM输出实验

    这里以TIM2为例 pwm c include pwm h uint16 t TIM2 CCR1 Val uint16 t TIM2 CCR2 Val uint16 t TIM2 CCR3 Val uint16 t TIM2 CCR4 Va
  • 【前端】HTML基础总结

    概要 html基本结构 nbsp 空格 emsp 空字符 html标签 h1 h1 标题标签1 6之间字体大小逐渐减小 p p 段落标签 b b 加粗 strong strong 加粗优化搜索 i i 斜体 div div 块级元素 spa
  • 数据结构学习——栈的应用:迷宫问题

    简介 基于栈的迷宫问题本质上是深度优先遍历 从起点开始深度优先搜索 遇到碰壁的情况时 根据栈的特性 可以 回溯 到之前走过的路 并继续搜索未搜索的方向 具体实现 我使用的ide是qt 它里面的一些图形库有助于我更加直观地理解深度优先搜索的过