文章目录

  • 一.算法概述
    • 迷宫如下:
    • 1.初始化迷宫并输出
    • 2.用二维数组记录是否到过迷宫中的点
    • 3.定义(1,1,3)为起始点坐标
    • 4.算法核心:
    • 5.循环结束,栈中从底到顶即为一条路线
    • 6.输出所有的路线,并求出最短路线
  • 二.具体代码实现:
  • 三.实验截图:

一.算法概述

迷宫如下:

        0 1 2 3 4 5 6 7 8 90 1 1 1 1 1 1 1 1 1 11    1 0 1 1 1 0 1 1 1 12    1 1 0 1 0 1 1 1 1 13    1 0 1 0 0 0 0 0 1 14    1 0 1 1 1 0 1 1 1 15    1 1 0 0 1 1 0 0 0 16    1 0 1 1 0 0 1 1 0 17    1 1 1 1 1 1 1 1 1 1

迷宫为8*6方阵
方向由1-8分别为上,右上,右,右下,下,左下,左,左上

1.初始化迷宫并输出

初始化一个长度10,宽度8二维数组,之所以要把长度宽度都加2,是因为需要一圈围墙来判断迷宫是否出界,并输入迷宫(注:这里我定义横向为长,纵向为宽,注意,在定义二维数组一定要maze[宽+2][长+2],也就是先宽再长)

2.用二维数组记录是否到过迷宫中的点

定义一个二维数组flag[Width+2][Length+2]记录各个点是否到过,是为1,否为0

3.定义(1,1,3)为起始点坐标

将当前坐标,当前方向定义为(1,1,3),即坐标(1,1)方向向右将flag[1][1]标记为1,初始化一个栈,用于保存路径。定义next_x,next_y保存下一待定坐标,为什么是待定呢?因为不一定能够走到,x,y为当前坐标

4.算法核心:

当下一个点的坐标不是终点坐标时,就用while一直循环遍历
即如果(next_x,next_y)不是(Length,Width),则一直循环
4.1.在进入方向循环之前,进行一次下一步待定坐标的求取
4.2.按照方向direction从1到8循环
4.2.1.求取下一步的待定坐标
4.2.2.判断这个待定坐标,如果下个点没来过(flag为0),并且下个点可以通行(maze为0)执行
{记录下来目前这个点的三个属性并将其压栈,沿着这个方向移动一次,
新到的点标记为来过(flag[y][x]=1)}
4.3.如果4.2.2中没有发生移动,证明走到了死角,保存走到死角之前的坐标,并将这个方向+1,再从这个新的坐标(走到死角之前的x,y坐标和这个+1后的方向)开始继续探索,然后把这个死角前坐标出栈
4.4.如果栈为空,那么迷宫无法出去

5.循环结束,栈中从底到顶即为一条路线

6.输出所有的路线,并求出最短路线

二.具体代码实现:

#include<iostream>
using namespace std;
void intend_move(int x,int y,int &next_x,int &next_y,int direction);//这个是修改下一步待定坐标的函数
void move(int &x,int &y,int &direction);//这个是修改当前坐标的函数
//链栈 注:由于不知道有多少个元素,所以用链栈可以省空间
template<class DataType>
struct Node
{DataType data;Node<DataType> *next;
};
template<class DataType>
class LinkStack
{public:LinkStack(){top=NULL;num=0;}~LinkStack(){};void Push(DataType x);DataType Pop();DataType GetTop(){if(top!=NULL)return top->data;}int Empty();int num;
private:Node<DataType> *top;
};
template<class DataType>//链栈入栈算法
void LinkStack<DataType>::Push(DataType x)
{Node<DataType> *s;s=new Node<DataType>;s->data=x;s->next=top;top=s;num++;
}
template<class DataType>//链栈出栈算法
DataType LinkStack<DataType>::Pop()
{Node<DataType> *p;p=new Node<DataType>;if(top==NULL)throw"下溢";DataType x=top->data;p=top;top=top->next;num--;delete p;return x;
}
template<class DataType>//判空操作
int LinkStack<DataType>::Empty()
{if(top==NULL)return 1;elsereturn 0;
}struct route
{int x;int y;int direction;
};
const int Length=8;
const int Width=6;
int main()
{/*      0 1 2 3 4 5 6 7 8 90    1 1 1 1 1 1 1 1 1 11    1 0 1 1 1 0 1 1 1 12    1 1 0 1 0 1 1 1 1 13    1 0 1 0 0 0 0 0 1 14    1 0 1 1 1 0 1 1 1 15    1 1 0 0 1 1 0 0 0 16    1 0 1 1 0 0 1 1 0 17    1 1 1 1 1 1 1 1 1 1//检验迷宫如图所示,0代表能通行,1代表不能通行,起点为maze[1][1],终点为maze[Width][Length]*/int i,j;bool maze[Width+2][Length+2]={{1,1,1,1,1,1,1,1,1,1},{1,0,0,1,1,0,0,1,1,1},{1,1,0,1,0,1,1,1,1,1},{1,0,1,0,0,0,0,0,1,1},{1,0,1,1,1,0,1,1,1,1},{1,1,0,0,1,1,0,0,0,1},{1,0,1,1,0,0,1,1,0,1},{1,1,1,1,1,1,1,1,1,1}};//初始化一个长度10,宽度8的二维数组,之所以要把长度宽度都加2,是因为需要一圈围墙来判断迷宫是否出界,并输入迷宫//注:这里我定义横向为长,纵向为宽,注意,在定义二维数组一定要maze[宽+2][长+2],也就是先宽再长cout<<"迷宫为:"<<endl;for(i=0;i<Width+2;i++){for(j=0;j<Length+2;j++)cout<<maze[i][j]<<" ";cout<<endl;}//输出迷宫bool flag[Width+2][Length+2]={0};//这个二维数组记录各个点是否到过,是为1,否为0//以下是求取路径算法LinkStack<route> Route;int x=1,y=1;int direction=1;//当前的坐标,当前的方向int next_x,next_y;//定义了下一步所走的点,如果x是横向的坐标,y是纵向的坐标,那么对应的点应该是maze[y][x]!!!这一点尤其注意,下面的同理,也需要这样表示int out_able=1;//设置标志,如果栈为空了,就把其置零,表明无法走出迷宫,否则说明走出了while循环且到达了目的地route NowNode;NowNode.x=1;NowNode.y=1;NowNode.direction=3;//起点,对应的是(1,1,右)flag[1][1]=1;//起点标记为来过cout<<"老鼠探索迷宫的路线为:"<<endl;while(next_x!=Length||next_y!=Width)//如果下一个坐标不是(8,6),这里要用到逻辑推理,A:x=8,B:y=6,出去的条件是AB,//那么 ′(AB)=′A U ′B,即next_x!=Length||next_y!=Width{int move_flag=0;//定义是否移动了,0为否,1为是for(direction=1;direction<=8;direction++)//按照方向direction从1到8循环{intend_move(x,y,next_x,next_y,direction);if(!flag[next_y][next_x]&&!maze[next_y][next_x])//如果下个点没来过(flag为0),并且下个点可以通行(maze为0)           {   NowNode.x=x;NowNode.y=y;NowNode.direction=direction;//记录下来目前这个点的三个属性Route.Push(NowNode);//把这个点压栈cout<<"("<<x<<","<<y<<","<<direction<<")\t";move(x,y,direction);//沿着这个方向移动一次flag[y][x]=1;//新到的点标记为来过move_flag=1;break;           }}if(!move_flag)//如果没有移动过,即move_flag=0,说明此路不通,把路线倒回去一个,即出栈一个元素,再走{cout<<"("<<x<<","<<y<<","<<0<<")\t";//输出死角坐标(死角坐标是当前的x,y值,并未压入栈)cout<<"("<<Route.GetTop().x<<","<<Route.GetTop().y<<","<<0<<")\t";//输出回退一个的坐标x=Route.GetTop().x;y=Route.GetTop().y;direction=Route.GetTop().direction+1;//Route.Pop();//要尤其注意这里的理解,走到死角之前的一个坐标方向是错的,所以这个点一定要出栈,但是在上一步中,我们已经保存了走到死角之前的那个坐标,所以就从死角前坐标的下一个方向再开始探索}if(Route.Empty()){cout<<"迷宫无法出去"<<endl;out_able=0;break;}}if(out_able)cout<<"终点(8,6,0)"<<endl;int t=0,num=Route.num;route *FinalRoute=new route[Route.num];for(;t<num;t++)FinalRoute[t]=Route.Pop();cout<<"一条路径为:";for(t=num-1;t>=0;t--)cout<<"("<<FinalRoute[t].x<<","<<FinalRoute[t].y<<","<<FinalRoute[t].direction<<")"<<" ";cout<<"终点(8,6,0)"<<endl;cout<<endl;return 0;
}//这个函数是用来计算下一个的坐标
void intend_move(int x,int y,int &next_x,int &next_y,int direction)//1,2,3,4,5,6,7,8所对应的是8个方向,从上、右上、右……左上分别对应1,2,3,4,5,6,7,8
{switch(direction){case 1:next_x=x;next_y=y-1;break;case 2:next_x=x+1;next_y=y-1;break;    case 3:next_x=x+1;next_y=y;break;case 4:next_x=x+1;next_y=y+1;break;case 5:next_x=x;next_y=y+1;break;case 6:next_x=x-1;next_y=y+1;break;case 7:next_x=x-1;next_y=y;break;case 8:next_x=x-1;next_y=y-1;break;}
}
void move(int &x,int &y,int &direction)
{switch(direction){case 1:x=x;y=y-1;break;case 2:x=x+1;y=y-1;break;    case 3:x=x+1;y=y;break;case 4:x=x+1;y=y+1;break;case 5:x=x;y=y+1;break;case 6:x=x-1;y=y+1;break;case 7:x=x-1;y=y;break;case 8:x=x-1;y=y-1;break;}direction=1;//移动后恢复坐标
}

三.实验截图:

数据结构——详解栈应用之迷宫问题相关推荐

  1. 万字长文的Redis五种数据结构详解(理论+实战),建议收藏。

    本文脑图 前言 Redis是基于c语言编写的开源非关系型内存数据库,可以用作数据库.缓存.消息中间件,这么优秀的东西一定要一点一点的吃透它. 关于Redis的文章之前也写过三篇,阅读量和读者的反映都还 ...

  2. redis数据结构详解之Hash(四)

    原文:redis数据结构详解之Hash(四) 序言 Hash数据结构累似c#中的dictionary,大家对数组应该比较了解,数组是通过索引快速定位到指定元素的,无论是访问数组的第一个元素还是最后一个 ...

  3. Python中的高级数据结构详解

    这篇文章主要介绍了Python中的高级数据结构详解,本文讲解了Collection.Array.Heapq.Bisect.Weakref.Copy以及Pprint这些数据结构的用法,需要的朋友可以参考 ...

  4. [转]Redis内部数据结构详解-sds

    本文是<Redis内部数据结构详解>系列的第二篇,讲述Redis中使用最多的一个基础数据结构:sds. 不管在哪门编程语言当中,字符串都几乎是使用最多的数据结构.sds正是在Redis中被 ...

  5. Redis数据结构详解之Zset(五)

    原文:Redis数据结构详解之Zset(五) 序言 Zset跟Set之间可以有并集运算,因为他们存储的数据字符串集合,不能有一样的成员出现在一个zset中,但是为什么有了set还要有zset呢?zse ...

  6. 【肝帝一周总结:全网最全最细】☀️Mysql 索引数据结构详解与索引优化☀️《❤️记得收藏❤️》

    [肝帝一周总结:全网最全最细]☀️Mysql 索引数据结构详解与索引优化☀️<❤️记得收藏❤️> 目录

  7. [redis] 10 种数据结构详解

    [redis] 10 种数据结构详解 简介 5种常见数据结构 string: 最常见的 string key value list: 双向链表 set: 集合- zset: 有序集合 hash: 类似 ...

  8. 数据结构详解——最大(小)左倾树

    数据结构详解--最大(小)左倾树 文章目录 数据结构详解--最大(小)左倾树 最大(小)左倾树的定义及用途 操作最大HBLT 合并操作 插入操作和删除操作 初始化操作 Java语言实现的最大HBLT ...

  9. 探索Redis设计与实现6:Redis内部数据结构详解——skiplist

    Redis内部数据结构详解(6)--skiplist  2016-10-05 本文是<Redis内部数据结构详解>系列的第六篇.在本文中,我们围绕一个Redis的内部数据结构--skipl ...

最新文章

  1. 在此处打开命令窗口_这样操作方便多了!简单DOS命令实用技巧详解
  2. delphi 调用php接口_贝壳找房小程序从PHP到Golang的跃迁之路
  3. queueing 优化_网站加载性能
  4. Angularjs调用公共方法与共享数据
  5. C# ArrayList 与 string、string[] 的转换
  6. python编辑七段数码管引脚图_初识原理图
  7. can接收id过滤linux,linux – 很大程度上被candump(SocketCAN)ID过滤功能搞糊涂了
  8. unity中调用dll文件总结
  9. 内存溢出的危害_漏洞练习之网络编程与堆栈溢出技术
  10. 时间序列(一):时间序列数据与时间序列预测模型
  11. FPGA丨图像二值化
  12. 九宫格日记-2011年03月03日
  13. 农夫山泉启示录:零售价2块钱的水,水值2分钱【姜太公公】
  14. python二元一次方程组用鸡兔同笼的思路来写编程_应用二元一次方程组——鸡兔同笼教学设计方案...
  15. 学计算机推荐电脑,计算机专业笔记本电脑推荐
  16. jira 工作日志导出 工具
  17. 攻击者可能会试图从item.taobao.com窃取您的信息 此服务器无法证明它是item.taobao.com;其安全证书来自*.tmall.com
  18. 研发团队管理:IT研发中项目和产品原来区别那么大,项目级的项目是项目,产品级的项目是产品!!!
  19. 蓝牙降噪耳机哪个比较好?四大热门降噪蓝牙耳机推荐
  20. C#首席设计师Anders Hejlsberg访谈

热门文章

  1. Mysql面试题总结(二)
  2. Ambari-2.7.5整合HDP-3.1.5集群完整安装记录(内附安Ambari-2.7.5 + HDP-3.1.5安装包下载地址)
  3. 马斯克的眼里,为什么总盯着何小鹏?
  4. 2018 GIS 软件技术大会在京举办,重磅嘉宾纵论行业发展
  5. php同时接受get post,PHP自学get和post数据同时提交的情形
  6. SOA架构/测试阶段接口描述语言转换方案
  7. base64入流出流区别
  8. 使用networkx绘制带节点坐标图(节点、节点坐标和边)
  9. 手把手教你PayPal[创建应用]、[创建商品]和[创建定期计划]
  10. 纵横网络靶场社区 Modbus协议