迷宫求解 数据结构实训报告 附源代码迷宫与栈 小老鼠吃奶酪穷举求解.docx

上传人:b****8 文档编号:10497895 上传时间:2023-02-14 格式:DOCX 页数:26 大小:153.10KB
下载 相关 举报
迷宫求解 数据结构实训报告 附源代码迷宫与栈 小老鼠吃奶酪穷举求解.docx_第1页
第1页 / 共26页
迷宫求解 数据结构实训报告 附源代码迷宫与栈 小老鼠吃奶酪穷举求解.docx_第2页
第2页 / 共26页
迷宫求解 数据结构实训报告 附源代码迷宫与栈 小老鼠吃奶酪穷举求解.docx_第3页
第3页 / 共26页
迷宫求解 数据结构实训报告 附源代码迷宫与栈 小老鼠吃奶酪穷举求解.docx_第4页
第4页 / 共26页
迷宫求解 数据结构实训报告 附源代码迷宫与栈 小老鼠吃奶酪穷举求解.docx_第5页
第5页 / 共26页
点击查看更多>>
下载资源
资源描述

迷宫求解 数据结构实训报告 附源代码迷宫与栈 小老鼠吃奶酪穷举求解.docx

《迷宫求解 数据结构实训报告 附源代码迷宫与栈 小老鼠吃奶酪穷举求解.docx》由会员分享,可在线阅读,更多相关《迷宫求解 数据结构实训报告 附源代码迷宫与栈 小老鼠吃奶酪穷举求解.docx(26页珍藏版)》请在冰豆网上搜索。

迷宫求解 数据结构实训报告 附源代码迷宫与栈 小老鼠吃奶酪穷举求解.docx

迷宫求解数据结构实训报告附源代码迷宫与栈小老鼠吃奶酪穷举求解

数据结构实训报告

设计题目:

迷宫的求解(B)

系别:

XXXXXXXXXX

专业(方向):

XXXXXXXX

年级、班:

XXXXXXXXXXXX

学生姓名:

XXX

学生学号:

XXXXXX

指导教师:

XXX

日期:

XXXX年XX月XX号

 

(一)测试迷宫与栈问题可通的程序设计…………..……………………………………10、11

(二)测试迷宫与栈问题不可通的程序设计…………………………………………..…..12

六、总结………………………………………………………………………………………….12、13

迷宫的求解

一、系统开发的背景

迷宫求解其实就是迷宫与栈的问题,训练老鼠在迷宫中寻找食物。

于是,老鼠过迷宫问题就此产生,这是一个很有趣的计算机问题,主要利用“栈”是老鼠通过尝试的办法从入口穿过迷宫走到出口。

迷宫只有两个门,一个叫做入口,另一个叫做出口。

把一只老鼠从一个无顶盖的大盒子的入口处赶进迷宫。

迷宫中设置很多隔壁,对前进方向形成了多处障碍,在迷宫的唯一出口处放置了一块奶酪,吸引老鼠在迷宫中寻找通路以到达出口。

为了使迷宫更佳富有趣味性,按照设计要求,我还设置地雷,如果老鼠在前进的过程中踩到地雷,则要重新回到入口,继续寻找能吃到奶酪的通路。

求解迷宫问题,即找出从入口到出口的路径。

而数据结构则是数据的组织形式,可以用来表示特定的对象数据,在计算机中对数据的一种存储和组织形式,因此选用栈思想实现迷宫游戏的基本操作,也是我设计迷宫求解的基本背景。

二、系统分析与设计

(一)系统分析:

迷宫问题通常是用“穷举求解”方法解决,即从入口出发,顺着某个方向进行搜索,若能走通,则继续往前走;否则沿着原路退回,换一个方向继续探索,直至出口位置,求得一条通路。

假如所有可能的通路都探索到而未能到达出口,则所设定的迷宫没有通路。

另外附加的老鼠踩地雷则类似于是在通路上埋藏的隐形墙,如果踩到到雷则返回起点,寻找下一条通路。

栈是一个后进先出的结构,可以用来保存从入口到当前位置的路径。

定义迷宫类型来存储迷宫数据,通常设定入口点的下标,出口点的下标,为处理方便起见,在迷宫的周围加一圈障碍,对于迷宫任何一个位置均约定为东、西、南、北四个方向,而东北、东南、西北、西南则是需要利用到两个下标进行移动。

(二)系统具体设计

在某个点上,按照一定的顺序(在本程序中顺序为上、右、下、左,而东北、东南、西北、西南利用的是两个下标移动)对周围的墙、路进行判断(在本程序中分别用1、0代替),若周围某个位置为0,则移动到该点上,再进行下一次判断;若周围的位置都为1(即没有通路),则一步步原路返回并判断有无其他通路,然后再次进行相同的判断,直到走到终点为止,或者确认没有任何通路后终止程序,附加踩雷(在本程序中用5代替)则返回到起点重新寻找下一条通路,并显示踩雷路线。

要实现上述算法,需要用到栈的思想。

栈里面压的是走过的路径,若遇到死路,则将该位置(在栈的顶层)弹出,再进行下一次判断;若遇到通路,则将该位置压栈并进行下一次判断。

如此反复循环,直到程序结束。

此时,若迷宫有通路,则栈中存储的是迷宫通路坐标的倒序排列,再把所有坐标顺序打印后,即可得到正确的迷宫通路,附加的踩雷则是相当于在通路上隐形了一道墙,踩雷,则从栈顶弹出,返回起点,再进行二次判断另一条通路。

三、系统功能要求

(1)首先实现一个以链表作存储结构的栈类型,然后编写一个求解迷宫的非归程序。

求得的通路以三元组(i,j,d)的形式输出。

其中:

(i,j)指示迷宫中的一个坐标,d表示走到下一坐标的方向。

如,对于下列数据的迷宫,输出一条通路为:

(1,1,1),(1,2,2),(2,2,2),(3,2,3),(3,1,2),…。

(2)编写递归形式的算法,求得迷宫中所有可能的通路。

(3)以方阵形式输出迷宫及其通路。

(一)系统模块结构设计

通过对系统功能的分析,迷宫与栈问题的功能如图1所示。

 

 

图1:

迷宫实现的主函数功能图

通过上图的功能分析,把整个系统划分为2个模块:

1、通过栈后进先出的结构,实现栈判断,首先判断栈是否为空,如果不为空,则实现栈中基本的入栈,出栈的实现。

顺序栈是用一组地址连续的内存单元依次保存栈中的运算规则,在链式存储中链表首部head指针所指向元素为栈顶元素,栈表尾部指向地址为NULL为栈底。

2、借助函数的嵌套与使用,由while语句对整体进行控制,return语句控制跳出函数,判断在迷宫中是否有出路,如果有出路,则通过东,西,南,北的方向进行路径的输出;如果无出路,则说明此迷宫不能走出。

四、系统的设计与实现

(一)在栈中实现迷宫的基本操作

分析:

首先输出表头,然后依次输入想要实现的步骤。

功能图如图2所示。

 

图2:

迷宫的实现功能图

该模块的具体代码如下所示。

voidMaze:

:

lujing(){

inti,j,d;

inta,b;

lianzhanelem,e;

PLStackS1,S2,S3;

InitStack(S1);

InitStack(S2);

InitStack(S3);

maze[start.x][start.y]=2;//入口点作上标记

elem.x=start.x;

elem.y=start.y;

elem.d=-1;//开始为-1

Push(S1,elem);

again:

while(!

StackEmpty(S1))//栈不为空有路径可走

{

Pop(S1,elem);

i=elem.x;

j=elem.y;

d=elem.d+1;//下一个方向

while(d<4)//试探东南西北各个方向

{

a=i+diradd[d][0];

b=j+diradd[d][1];

if(maze[a][b]==5)

{

while(S1)//逆置序列并输出迷宫路径序列

{

Pop(S1,e);

Push(S3,e);

}

maze[a][b]=1;

for(i=0;i

for(j=0;j

{

if(maze[a][b]==2)

maze[a][b]=0;

}

cout<<"\n0=东1=南2=西3=北4=走出迷宫\n\n通路为(横坐标,列坐标,方向):

\n";

while(S3)

{

Pop(S3,e);

Push(S1,e);

cout<<"-->{"<

}

cout<<"\n你在"<<"["<

d=0;

gotoagain;

}

if(a==end.x&&b==end.y&&maze[a][b]==0)//如果到了出口

{

elem.x=i;

elem.y=j;

elem.d=d;

Push(S1,elem);

elem.x=a;

elem.y=b;

elem.d=4;//方向输出为-1判断是否到了出口

Push(S1,elem);

cout<<"\n0=东1=南2=西3=北4=走出迷宫\n\n通路为(横坐标,列坐标,方向):

\n";

while(S1)//逆置序列并输出迷宫路径序列

{

Pop(S1,e);

Push(S2,e);

}

while(S2)

{

Pop(S2,e);

cout<<"-->{"<

}

return;//选用return跳出两层循环

}

if(maze[a][b]==0)//找到可以前进的非出口的点

{

maze[a][b]=2;//标记走过此点

elem.x=i;

elem.y=j;

elem.d=d;

Push(S1,elem);//当前位置入栈

i=a;//下一点转化为当前点

j=b;

d=-1;

}

d++;

}

}

cout<<"抱歉,小老鼠走投无路没有吃到奶酪!

"<

}

(二)栈的生成

 

图3:

栈的实现功能图

 

该模块的具体代码如下所示。

Maze:

:

Maze()

{

}

Maze:

:

~Maze()

{

}

intMaze:

:

InitStack(PLStack&S)//构造空栈

{

S=NULL;

return1;

}

intMaze:

:

StackEmpty(PLStackS)//判断栈是否为空

{

if(S==NULL)

return1;

else

return0;

}

intMaze:

:

Push(PLStack&S,lianzhane)//在栈中放入一个新的数据元素(进栈)

{

PLStackp;

p=(PLStack)malloc(sizeof(LStack));//申请新的栈顶结点空间

p->elem=e;//将元素值置入结点数据域

p->next=S;//原栈顶结点昨晚新结点后继

S=p;//将新结点置为栈顶

return1;

}

intMaze:

:

Pop(PLStack&S,lianzhan&e)//栈顶元素出栈

{

PLStackp;

if(!

StackEmpty(S))

{

e=S->elem;

p=S;

S=S->next;

deletep;//释放结点

return1;

}

else

return0;

}

 

(三)整个系统的生成流程图

 

 

N

Y

 

YN

Y

YN

YN

N

 

Y

 

五、程序测试与步骤

(一)测试迷宫与栈问题的可通程序设计

测试该函数使用的测试方法,测试的具体步骤,测试用例的选取,测试的结果。

图4:

在测试中可以找到迷宫和踩雷路径

 

(二)测试迷宫与栈问题的不可通程序设计

测试该函数使用的测试方法,测试的具体步骤,测试用例的选取,测试的结果。

图5:

在测试中并未找到迷宫路径

 

六、总结

迷宫求解首先实现了随机输入m和n的值,自己设定一个矩阵的行与列,在给定空间内控制了迷宫的范围,再从电脑中输入“0”为通路,“1”为围墙显示出一个迷宫的雏形来,最终通过for循环给写好的迷宫加一个围墙,得到我们想要的结果,并且给定迷宫的入口和出口,从而寻找到迷宫的可同路径或者说入口处进入后,并不能找到可通路径从而退出。

而我定义“5”为地雷,这样小老鼠就能愉快的踩雷回到起点了,重新进行下一步的通路探测。

也可以循环使用此程序。

系统在设计过程中我只考虑到了迷宫中给定入口和出口,在选择路径时仅有东、西、南、北,这四个方向寻找出口,而不是更加全面的在东南、东北、西南、西北,方向同时寻找迷宫的出路,因此这一点是我认为考虑很不周到的,但是我已经对这个功能有了初步设想,利用移动两次下标进行东南、东北、西南、西北的方向实现,希望能够在今后的学习中更好的完善,让这个迷宫求解更加的充实。

我的收获是这次的课程设计的内容是使用C++和数据结构来实现栈的应用,这对我来说是个很具有挑战性的任务,虽然只做了一个迷宫与栈的问题,而且运行起来有很大的局限性,但通过两星期的设计也从中学到了不少的东西,更多的了解到了课本中丰富的内容。

《数据结构》是一门实践性较强的课程,为了学好这门课程,必须在掌握理论知识的同时,加强上机实践。

同时再次深刻的了解了数据结构中数组与基本函数之间的调用,并且使用顺序结构,选择结构,循环结构的嵌套,根据实际问题的需要实现迷宫与栈问题。

在本次课程设计中,我明白了理论与实际相结合的重要性,并提高了自己组织数据及编写程序的能力,挺高了综合运用所学知识的能力。

七、附件(代码、部分图表)

#include

usingnamespacestd;

#defineM20//行

#defineN20//列

intm,n;

intdiradd[4][2]={{0,1},{1,0},{0,-1},{-1,0}};//行增量和列增量方向依次为东西南北

structZuobiao//定义迷宫内点的坐标类型

{

intx;

inty;

};

structlianzhan//链栈元素

{

intx,y;//x行,y列

intd;//d为下一步的方向

};

typedefstructLStack//链栈

{

lianzhanelem;

structLStack*next;

}*PLStack;

/*************栈函数****************/

classMaze

{

public:

Maze();

~Maze();

intInitStack(PLStack&S);//构造空栈

intStackEmpty(PLStackS);//判断栈是否为空

intPush(PLStack&S,lianzhane);//在栈中放入一个新的数据元素(进栈)

intPop(PLStack&S,lianzhan&e);//栈顶元素出栈

/***************求迷宫路径函数***********************/

voidlujing();

voidinitmaze();

voidinput();

private:

intmaze[M][N];

structZuobiaostart,end;//start,end入口和出口的坐标

};

 

intmain()

{

ints;

Mazeexample;

cout<<"***********************************************************************"<

cout<<"*********小老鼠吃奶酪*********"<

cout<<"***********************************************************************"<

cout<<"***********************************************************************"<

cout<<"***********************************************************************"<

example.initmaze();//建立迷宫

example.input();//输入

example.lujing();//路径

cout<

cout<

cout<

cout<<"***********************************************************************"<

cout<<"<<@@@@@按‘1’则可以继续玩游戏,按任意键‘GAMEOVER’!

@@@@@>>";

cin>>s;

if(s==1)

main();

else

cout<<"#####‘GAMEOVER!

’#####\n谢谢进入迷宫游戏!

"<

return0;

}

Maze:

:

Maze()

{

}

Maze:

:

~Maze()

{

}

intMaze:

:

InitStack(PLStack&S)//构造空栈

{

S=NULL;

return1;

}

intMaze:

:

StackEmpty(PLStackS)//判断栈是否为空

{

if(S==NULL)

return1;

else

return0;

}

intMaze:

:

Push(PLStack&S,lianzhane)//在栈中放入一个新的数据元素(进栈)

{

PLStackp;

p=(PLStack)malloc(sizeof(LStack));//申请新的栈顶结点空间

p->elem=e;//将元素值置入结点数据域

p->next=S;//原栈顶结点昨晚新结点后继

S=p;//将新结点置为栈顶

return1;

}

intMaze:

:

Pop(PLStack&S,lianzhan&e)//栈顶元素出栈

{

PLStackp;

if(!

StackEmpty(S))

{

e=S->elem;

p=S;

S=S->next;

deletep;//释放结点

return1;

}

else

return0;

}

/***************求迷宫路径函数***********************/

voidMaze:

:

lujing(){

inti,j,d;

inta,b;

lianzhanelem,e;

PLStackS1,S2,S3;

InitStack(S1);

InitStack(S2);

InitStack(S3);

maze[start.x][start.y]=2;//入口点作上标记

elem.x=start.x;

elem.y=start.y;

elem.d=-1;//开始为-1

Push(S1,elem);

again:

while(!

StackEmpty(S1))//栈不为空有路径可走

{

Pop(S1,elem);

i=elem.x;

j=elem.y;

d=elem.d+1;//下一个方向

while(d<4)//试探东南西北各个方向

{

a=i+diradd[d][0];

b=j+diradd[d][1];

if(maze[a][b]==5)

{

while(S1)//逆置序列并输出迷宫路径序列

{

Pop(S1,e);

Push(S3,e);

}

maze[a][b]=1;

for(i=0;i

for(j=0;j

{

if(maze[a][b]==2)

maze[a][b]=0;

}

cout<<"\n0=东1=南2=西3=北4=走出迷宫\n\n通路为(横坐标,列坐标,方向):

\n";

while(S3)

{

Pop(S3,e);

Push(S1,e);

cout<<"-->{"<

}

cout<<"\n你在"<<"["<

d=0;

gotoagain;

}

if(a==end.x&&b==end.y&&maze[a][b]==0)//如果到了出口

{

elem.x=i;

elem.y=j;

elem.d=d;

Push(S1,elem);

elem.x=a;

elem.y=b;

elem.d=4;//方向输出为-1判断是否到了出口

Push(S1,elem);

cout<<"\n0=东1=南2=西3=北4=走出迷宫\n\n通路为(横坐标,列坐标,方向):

\n";

while(S1)//逆置序列并输出迷宫路径序列

{

Pop(S1,e);

Push(S2,e);

}

while(S2)

{

Pop(S2,e);

cout<<"-->{"<

}

return;//选用return跳出两层循环

}

if(maze[a][b]==0)//找到可以前进的非出口的点

{

maze[a][b]=2;//标记走过此点

elem.x=i;

elem.y=j;

elem.d=d;

Push(S1,elem);//当前位置入栈

i=a;//下一点转化为当前点

j=b;

d=-1;

}

d++;

}

}

cout<<"抱歉,小老鼠走投无路没有吃到奶酪!

"<

}

/*************建立迷宫*******************/

voidMaze:

:

initmaze()

{

inti,j;

//迷宫行,列

cout<<"请输入迷宫的行数:

m=";

cin>>m;

cout<<"请输入迷宫的列数:

n=";

cin>>n;

cout<<"*******************************************

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 管理学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1