【数据结构】迷宫问题实现(包含界面)

这篇具有很好参考价值的文章主要介绍了【数据结构】迷宫问题实现(包含界面)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🎈🎈

问题描述:假设迷宫由m行n列构成,有一个入口和一个出口,入口坐标为(1,1),出口坐标为(m,n),试设计并验证一下算法:找出一条入口通往出口的路径,或报告一个"无法通过"的信息。

具体需求如下:

  1. 用C语言实现顺序存储结构上队列的基本操作,然后利用该队列的基本操作找出迷宫的一条最短路径。

  1. 设计一个二维数组MAZE[m+2][n+2]表示迷宫,数组元素为0表示该位置可以通过,数组元素为1表示该位置不可以通行。MAZE[1][1],MAZE[m][n]分别表示为迷宫的出口和入口。

  1. 输入迷宫的大小m行和n列,动态生成二维数组;由随机数产生0或1

  1. 迷宫的任意位置上均有八个可以移动的方向。

  1. 若存在走出迷宫的路径,则动态展示走出迷宫的过程。

✨✨

先给大家看看最终的运行效果:

①.未找到路径的情况

数组 迷宫,数据结构,数据结构,c语言,Powered by 金山文档

②.找到最短路径,并动态演示从起点走到终点的过程

数组 迷宫,数据结构,数据结构,c语言,Powered by 金山文档

OK,我愿称之为史上最变态迷宫问题——不仅有八个移动方向,还要设计界面,动态展示走出迷宫的过程。话不多说,我们现在来一步步实现迷宫算法吧!

注:此迷宫用c语言实现,界面用的是c++。当然了,我们主要是理解迷宫的实现算法(也就是c语言写的代码),图形界面可以随便选c、c++或者别的高级语言实现。


算法实现步骤:

  1. 实现顺序存储结构上队列的基本操作

这个我就不详细说明了,直接给老铁们上源码链接:

顺序队列的实现


  1. 动态创建迷宫

创建迷宫我们分两步:

①.动态创建二维数组并初始化为0

这里我们使用malloc函数即可实现数组的动态创建,代码如下:

int** CreateArray(int m, int n) {
    int i, j;
    int** array;
    array = (int**)malloc((m)*sizeof(int*));
    for(i=0; i<m; i++) {
        array[i] = (int*)malloc(sizeof(int)*(n));
    }
    for(i=0; i<m; i++) {
        for(j=0; j<n; j++) {
            array[i][j] = 0;//初始化为0
        }
    }
    return array;
}

(1) 建立迷宫,注意m*n的迷宫需要进行扩展,即实际迷宫大小为(m+2)*(n+2),扩展部分的元素设置为1。这是因为C语言不会进行数组越界检查,为了防止我们在找路径时会跑到迷宫之外的存储位置上,要给迷宫“围上一堵墙”。

(2)CreatyArray函数并未体现创建了(m+2)*(n+2)的数组,这是因为我给次函数传递的实参为(m+2,n+2)。即实际调用时为“CreatyArray(m+2, n+2);”

②.随机给数组元素赋1——0表示可行,1表示不可行

随机赋值也比较简单,使用随机函数srand()即可

代码如下:

int** MakeMaze(int m, int n) {
    int i, j;
    int** maze;
    srand(time(0));
    maze = CreateArray(m+2, n+2);
    for(i = 0; i<n+2; i++) {
        maze[0][i] = 1;
        maze[m+1][i] = 1;
    }
    for(i = 0; i<m+2; i++) {
        maze[i][0] = 1;
        maze[i][n+1] = 1;
    }
    for(i=1; i<m+1; i++) {
        for(j=1; j<n+1; j++) {
            maze[i][j] = rand()%2%2;
        }
    }
    maze[1][1] = maze[m][n] = 0;
    return maze;
}

注:

(1)连续两次%2可以使元素为0概率变大,即该迷宫存在路径的可能性更大。(哈哈,我们老师说的,我没去深究)

(2)迷宫入口maze[1][1]和迷宫出口maze[m][n]必须可行,即值为0


  1. 判断是否存在走出迷宫的路径

这个算法实际上是找出走出迷宫的所有可能路径,用到了顺序队列

算法思想:

  • 首先将入口入队,以入口为起点判断其八个方向的点是否可行,如果可行就将该点入队。

  • 当队列不空并且未到达终点时,继续对队列的队头元素判断其八个方向的点是否可行,如果可行就将该点入队。

  • 每判断完队列中的一个队头元素,就将该队头元素出队,并获取下一个队头元素。这里的出队其实是逻辑上的出队,是队列的头指针指向了下一个元素。

因此,其实我们一直都是对队列的队头元素判断其八个方向,并重复对队列进行入队出队操作。

我们最好边画图边看代码,有助于理解寻找路径的过程。

代码如下:

Status IfHaveWay(int** maze, int m, int n, SqQueue* Q) {
    int i, success = 0, m2, n2, count = 0;
    QElemType head = {1,1,-1, 0}, e;
    int** flag = CreateArray(m+2, n+2);//标志数组
    int direction[8][2] = {{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};//存放八个方向的位置偏移量
    flag[1][1] = 1;
    EnQueue(Q, head);
    while(!success && !QueueEmpty(*Q)) {
        for(i=0; i<8; i++) {
            m2 = head.row+direction[i][0];//迷宫的行
            n2 = head.column+direction[i][1];//迷宫的列
            if(maze[m2][n2] == 0 && flag[m2][n2] == 0) { //该点未被走过
                e.row = m2;
                e.column =n2;
                e.pre = head.pos;
                e.pos = QueueLength(*Q)+count;
                EnQueue(Q, e);
                flag[m2][n2] = 1;
            }
            if(e.row == m && e.column == n) {
                success = 1;//找到出口,退出循环
                break;
            }

        }
        DeQueue(Q, &e);
        GetHead(*Q, &head);
        count++;
    }
    if(!success)
        return FALSE;
    else
        return TRUE;
}

  1. 若存在路径,则找出最短路径

在上一步的判断路径是否存在过程中我们已经得到了一个顺序队列,里面是走出迷宫的全部可能路径。

那么如何从这些路径中找出最短路径呢?方法很简单:

  • 初始化栈S

  • 从得到的顺序队列队尾元素开始,依次找元素的前驱,并存入栈中,直至起点(1,1),这样可以找到最短路径。

又因为栈是“先进后出”的,所以从栈顶至栈底即为走出迷宫的路径。

注:

最好画图理解,光看文字和代码十分抽象。

代码如下:

SqStack FindWay(SqQueue Q) {
    SqStack S;
    InitStack(&S);
    SElemType tmp;
    int p = Q.rear-1, pre = Q.base[p].pre;
    tmp.column = Q.base[p].column;
    tmp.pos = Q.base[p].pos;
    tmp.pre =  Q.base[p].pre;
    tmp.row = Q.base[p].row;
    Push(&S, tmp);
    p--;
    while(p>=0) {
        if(pre == Q.base[p].pos) {
            tmp.column = Q.base[p].column;
            tmp.pos = Q.base[p].pos;
            tmp.pre =  Q.base[p].pre;
            tmp.row = Q.base[p].row;
            Push(&S, tmp);
            pre = Q.base[p].pre;
        }
        p--;

    }
    return S;

}

  1. 实现迷宫的图形化界面设计

代码如下:

#include "widget.h"
#include<maze.h>
#include "ui_widget.h"
#include <QColor>
#include <QTimer>
#include <QMessageBox>
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget){

    ui->setupUi(this);
    this->people.load(":/Image/people.png");
    this->sign.load(":/Image/flag.png");
    this->wall.load(":/Image/wall.png");
}

Widget::~Widget()
{

    delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
    if(m!=0 && n!= 0){
        QPainter painter(this);// 实例化画家对象,this指定的是绘图设备
        for(int i=0;i<=m+2;i++){
            painter.drawLine(i*60+25,25,i*60+25,(m+2)*60+25);// 画竖线
        }
        for(int i=0;i<=n+2;i++){
               painter.drawLine(25,i*60+25,(n+2)*60+25,i*60+25);//画横线
          }

        // 设置画笔
        QPen pen(QColor(255,0,0));
        // 设置画笔宽度
        pen.setWidth(2);
        pen.setStyle(Qt::SolidLine);//设置画笔样式
        painter.setRenderHint(QPainter::Antialiasing);//抗锯齿
        painter.setPen(pen);
        for(int i=0;i<m+2;i++)
        {
            for(int j=0;j<n+2;j++)
            {
                if(maze[i][j]==1)
                {
                     painter.drawPixmap(i*60+30,(j)*60+28,this->wall);

                }
            }
        }
        painter.drawPixmap(posX,posY,this->people);//画运动的人
        painter.drawPixmap(m*60+45,(n)*60+40,this->sign);//画终点的图标
    }
}

void Widget::on_checkBt_clicked()//确定按钮点击事件
{
    SqStack SWay;
    SqQueue Q;
    SElemType tmp;
    InitStack(&SWay);
    m = ui->maze_m->text().toInt();
    n = ui->maze_n->text().toInt();
    QMessageBox *mbox = new QMessageBox();
    mbox->setIcon(QMessageBox::Information);
    if(n != 0 && m != 0){
        this->maze = MakeMaze(m, n);
        InitQueue(&Q);
        if(!IfHaveWay(maze, m,n, &Q)) {
            mbox->setText("未找到走出迷宫的路径");
            mbox->show();
            update();
        }else{//找到路径
            QTimer *timer = new QTimer(this);//设置定时器
            timer->start(1000);
            SWay = FindWay(Q);

            connect(timer,&QTimer::timeout,[=](){
                if(StackEmpty(SWay)){//栈为空,说明路径已走完
                    timer->stop();
                    mbox->setText("成功走出迷宫,Congratulations!");
                    mbox->show();
                    posX = 90, posY = 90;
                    update();
                    return;
                }
                Pop((SqStack*)(&SWay), (SElemType*)(&tmp));//将存放路径的栈的元素依次弹出
                posX = tmp.row*60+30, this->posY = tmp.column*60+30;
                update();
            });
        }
    }else{
        mbox->setText("请输入有效的长和宽");
        mbox->show();
    }
}

最后给大家贴个我实现迷宫用到的文件截图:

数组 迷宫,数据结构,数据结构,c语言,Powered by 金山文档

经历了以上步骤,我们的迷宫终于设计好了,是不是感觉也没有那么难呢。有疑问的朋友可以在评论区留言或者私信(关于界面设计的代码就算了哈,我不太会c++)


最后的最后,喜欢的朋友请点个赞吧(想要源码记得三连并私信喔)~❤🧡💛💚💙💜💗文章来源地址https://www.toymoban.com/news/detail-767250.html

到了这里,关于【数据结构】迷宫问题实现(包含界面)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C数据结构】迷宫问题

    前言: 本章记录作者学习中,遇到的两个比较有趣的问题,一个简单和一个较复杂的迷宫问题。     让我们先来看简单的:迷宫问题 它的具体要求: 输入描述: 输入两个整数,分别表示二维数组的行数,列数。再输入相应的数组,其中的 1表示墙壁 , 0表示可以走的路 。

    2024年02月02日
    浏览(41)
  • 数据结构——迷宫问题(顺序栈、C++)

     讲解: 一、采用二维数组和srand函数随机生成只有0和1的迷宫。 二、求解迷宫大概思路:先将入口处的坐标即方向d入栈,然后当栈不为空时,取出栈顶(即当前节点)的数据。遍历当前节点的四个方向,找到可行的下一个节点,并将其入栈;如没有可行的下一个节点,则将

    2024年02月13日
    浏览(34)
  • 《数据结构与算法分析》课程设计——迷宫问题

    中国矿业大学信控学院   补一下我之前在博客园发布的内容  懒得调了, 想复制完整代码直接复制最下面的 ,想复制分布代码去看我博客园链接吧 《数据结构与算法分析》课程设计——迷宫问题 - 刷子zz - 博客园 一、  问题描述 问题中迷宫可用方阵[m,n]表示,0表示能通过

    2024年02月10日
    浏览(49)
  • 数据结构-线性表的链式存储(包含代码实现)

    链式存储结构 结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻 线性表的链式存储结构又称为 非顺序映像 或 链式映像。 用一组 物理位置任意的存储单元 来存放线性表的数据元素 这组存储单元既可以是连续的,也可以是不连续的,甚至是零散

    2024年02月06日
    浏览(52)
  • 数据结构--迷宫求解

    文章目录 一、问题的描述 二、系统功能设计 三、各个代码部分 四、整体代码及其运行 五、总结 迷宫求解--C语言 在一个迷宫中,需要我们找到出去的道路,并且得到的路经是最短的。 迷宫设置如下:迷宫使用标记(0,1,2,3分别代表迷宫的墙壁,通道,入口和出口) 从开

    2024年02月15日
    浏览(40)
  • 数据结构线性结构(二)6迷宫最短路径

       

    2024年02月08日
    浏览(33)
  • C数据结构与算法——队列 应用(C语言纯享版 迷宫)

    实验任务 (1) 掌握顺序循环队列及其C语言的表示; (2) 掌握入队、出队等基本算法的实现; (3) 掌握顺序循环队列的基本应用(求解迷宫通路)。 实验内容 使用C语言实现顺序循环队列的类型定义与算法函数; 编写main()函数并根据需要修改、补充相关的类型定义与函数,以实

    2024年02月15日
    浏览(52)
  • C语言 / 数据结构中出现报错: 表达式必须包含算数或指针类型,但他具有类型 “XXX” 。 报错问题的解决 以及 方法

    前提介绍:L3 是一个结构体的地址,是一个指针  elem是该结构体内的一个结构体元素,elem是一个数组 算数类型是什么? 下该文章最下面 报错显示, 表达式必须包含 算数 或 指针类型 , 但elem是一个数组,它的类型明显不是指针类型, 那么elem 的类型本质上应该就是一个算

    2024年02月09日
    浏览(43)
  • 数据结构与算法大作业:走迷宫程序(C语言,DFS)(代码以及思路)

    好家伙,写大作业,本篇为代码的思路讲解   问题描述: 以一个 m * n 的长方阵表示迷宫, 0和1分别表示迷宫的通路和障碍。 设计一个程序, 对任意设定的迷宫, 求出一条从入口到出口的通路, 或得出没有通路的结论。 基本要求: (1) 实现一个以链表做存储的栈类型,

    2024年02月03日
    浏览(40)
  • 【Python数据结构与算法】--- 递归算法的应用 ---[乌龟走迷宫] |人工智能|探索扫地机器人工作原理

    🌈个人主页: Aileen_0v0 🔥系列专栏:PYTHON数据结构与算法学习系列专栏 💫\\\"没有罗马,那就自己创造罗马~\\\"  目录 导言  解决过程  1.建立数据结构 2.探索迷宫: 算法思路 递归调用的“基本结束条件” 3.乌龟走迷宫的实现代码: 运行过程: 拓展: 📝全文总结:  乌龟探索迷宫这个问

    2024年02月05日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包