迷宫实验报告.docx
《迷宫实验报告.docx》由会员分享,可在线阅读,更多相关《迷宫实验报告.docx(31页珍藏版)》请在冰豆网上搜索。
迷宫实验报告
迷宫实验报告
LT
4、程序完成对迷宫路径的搜索,为了更好地显示出求解结果,如果存在路径,则以长方形形式将迷宫打印出来,而不是只按步输出坐标,也便于检查路径的正确性,用特定符号标出迷宫的物理状态,其中字符“#”表示出口和入口,“<”标记出可行的路径;如果程序完成搜索后没有找到通路,则提示用户“NoPath!
”。
如图所示:
5、程序执行的命令:
⑴创建初始化迷宫;
⑵搜索迷宫;
⑶输出搜索到的最短路径。
一、概要设计
(按照题目要求应该用队列实现路径的存储,但操作过程中遇到很多困难未能解决,故选择栈的操作来实现路径的存储)
1、迷宫的抽象数据类型定义:
ADTMaze{
数据对象:
D:
={aij,Start,end|-20<=aij<20,Start,end∈{(i,j)|0≤i≤m+2,0≤j≤n+2,m,n≥0}}
数据关系:
R={length,width}
length={|ai-1,aij∈Di=1,…,m+2,j=1,…,n+2}
width={|aijaij-1∈D}
基本操作:
SetMaze(&M)
初始条件:
M已经定义,M的下属单元二维数组M.Maze[row+2][d+2]已存在,M.start,M.end也已作为下属存储单元存在
操作结果:
构成数据迷宫,用数值标识迷宫的物理状态,以0表示通路,以1表示障碍,由终端读取迷宫空间大小,各点处的具体物理状态及Start和End点位置,完成迷宫构建
Pass(M,CurPos)
初始条件:
已知目前迷宫状态及当前位置
操作结果:
完成相应的搜索任务,如果可行,则返回1
NextPos(CurPos,directionr)
操作结果:
返回CurPOS位置在方向direction上的下一位置
SameSeat(Path,row,col)
操作结果:
若(row,col)位置是路径Path中的一个点,则返回TRUE
PrintMaze(M)
初始条件:
迷宫M已存在
操作结果:
输出字符标示的迷宫
MazePath(M,&Path)
初始条件:
迷宫M已存在
操作结果:
搜索迷宫,用path返回搜索所得路径。
如不存在,返回0
PrintPath(M,Path)
初始条件:
迷宫M已存在
操作结果:
迷宫M存在可行路径则将迷宫M及相应最短路径一起打印输出
}ADTMAZE;
⒊本程序模块结构
⑴主函数模块
voidmain(){
初始化迷宫和栈;
创建迷宫;
输出迷宫;
搜索路径;
输出路径;
}
⑵栈模块——实现栈抽象数据类型;
⑶迷宫模块——实现迷宫抽象数据类型;
各模块之间的调用关系如下:
主程序模块
迷宫模块
栈模块
二、详细设计
1、基本数据类型操作
⑴栈模块
①typedefstruct{
intorder;
Positionseat;
intdirection;
}SElemType;//步数、方向及位置
//栈定义
②typedefstructlnode{
SElemType*base;
SElemType*top;//设两指针便于判断栈是否为空
intstacksize;//栈当前可使用的最大容量
}SqStack;
③参数设置:
#defineSTACK_INIT_SIZE100
#defineSTACKINCRENT10
//----------基本操作的算法描述--------------------
StatusInitStack(SqStack&s){//构造一个空栈
S.base=(SelemType)malloc(STACK_INIT_SIZE*SizeOf(SelemType));
if(!
S.base)exit(OVERLOW);//存储分配失败
S.top=S.base;
S.stacksize=STACK_INIT_SIZE;
returnok;
}
StatusStackEmpty(Sqstack&S){//若S为空返回TRUE,否则返回FALSE
returnS.base==S.top;
}
StatusGetTop(SqStack&S,Selemtype&e){
//栈不空,用e返回s的栈顶元素及OK,否则返回ERROR
if(S.top==S.base)returnERROR;
e=*(S.top-1);
returnok;
}
StatusPush(Sqstack&S,SelemType&e){//插入元素e为新的栈顶元素
if(S.top-S.base>=S.stacksize){//栈满追加存储空间
S.base=(SelemType)realloc(S.base,(S.stacksize+STACKICREMENT)Sizeof(Selemtype));
if(!
S.base)exit(OVERFLOW)//存储分配失败
S.top=S.base+S.stacksize;//确定新的栈顶指针
S.stacksize+=STACKINCREMENT;//已分配空间增加
}
*S.top++=*e;
returnok;
}
StatusPop(Sqstack&s,SelemType&e){
//若栈不变,则删除栈顶元素,用e返回其值及ok,否则false
if(S.top=o=S.base)
returnERROR;
*e=*--S.top;//顶指针减小,用e返回其数据
returnok;
}
⑵迷宫模块:
①迷宫的数据类型
#defineMAXLENGTH50//迷宫的最大长度
#defineMAXWIDTH50//屏幕宽度,迷宫的最大宽度
//元素类型
typedefintStatus;
typedefstruct{
introw;
intcol;
}Position;//位置坐标
//迷宫定义
typedefintElemType;
typedefstructMAZE{
ElemTypeMaze[MAXLENGTH][MAXWIDTH];//迷宫的物理状态描述
intlength,width;//迷宫的大小
Positionstart,end;//开始与结束位置与栈的单元类型相同
}MAZE;//“迷宫”型数据
②迷宫模块中的基本操作
Statussemaze(MAZE&M){
Printf(“PleaseinputthelengthandwidthoftheMAZE”);
sanf(“rlength,width”);
for(k=0;kM->Maze[0][k]=1;
for(j=0;jM->Maze[j][0]=1;
for(j=0;jM->Maze[j][width+1]=1;
for(k=0;kM->Maze[length+1][k]=1;//设置迷宫围墙
for(j=1;j<=length;j++)
{
for(k=1;k<=width;k++)
M->Maze[j][k]=rand()%2;//随机生成迷宫
}
M->length=length;
M->width=width;
M->start.row=1;
M->start.col=1;
M->end.row=M->length;
M->end.col=M->width;
M->Maze[M->start.row][M->start.col]=M->Maze[M->end.row][M->end.col]=0;//入口和出口设置*/
}
voidPrintMaze(MAZEM){//打印出迷宫,包括边界
printf("迷宫入口:
[1,1]--用#表示\n");
printf("迷宫出口:
[%d,%d]--用#表示\n",M.length,M.width);
for(row=0;rowfor(col=0;colif((row==1&&col==1)||(row==M.length&&col==M.width))
printf("#");//入口和出口用#表示
else
printf("%c",M.Maze[row][col]);
}
printf("\n");
}//用字符型打印输出(i,j)状态
}
StatusPass(MAZEM,PositionCurPos){
//判断迷宫中当前位置CurPos上能否通过
//如果通过返回1
if(M.Maze[CurPos.row][CurPos.col]==0)
return1;//如果当前位置是可以通过,返回1
elsereturn0;//其它情况返回0
}
PositionNextPos(PositionCurPos,intdirection){
//返回当前位置在direction方向上的下一位置
ReturnPos.row=CurPos.row+Direction[direction-1][0];
ReturnPos.col=CurPos.col+Direction[direction-1][1];
returnReturnPos;
}
StatusSameSeat(SqStackPath,introw,intcol){
//位置(row,col)在路径中时返回TRUE
while(pif(Path.base[num].seat.row==row&&Path.base[num].seat.col==col)//路径某一步所在的位置
returnTRUE;
num++;
p++;
}
returnFALSE;
}
StatusMazePath(MAZEM,SqStack*S){
//若迷宫maze中从入口start到出口end的通道,则求得一条存放在栈中
//(从栈底到栈顶),并返回SUCCESS;否则返回FAIL
curpos=M.start;//设定"当前位置"为"入口位置"
curstep=1;//探索第一步
//第一次查找路径,设置5个方向(不远离!
终点的五个方向),若找到则返回SUCCESS
do{
if(Pass(M,curpos)){//当前位置可通过,即是未曾走到过的通道块
M.Maze[curpos.row][curpos.col]='';//留下足迹
e.direction=1;
e.order=curstep;
e.seat=curpos;
Push(S,&e);//加入路径
if(curpos.row==M.end.row&&curpos.col==M.end.col){
//到达终点(出口)
returnSUCCESS;
}
curpos=NextPos(curpos,1);//下一位置在当前位置的右下方
curstep++;//探索下一步
}
else{//当前位置不能通过
if(!
StackEmpty(S)){
Pop(S,&e);
while(e.direction==5&&!
StackEmpty(S)){
M.Maze[curpos.row][curpos.col]='';//标记不能通过
Pop(S,&e);//留下不能通过的标记,并退回一步
}//while
if(e.direction<5){
e.direction++;
GetTop(S,&te);
if(e.direction==5&&te.direction==2){
Pop(S,&e);
e.direction++;
}
Push(S,&e);//换下一个方向探索
curpos=NextPos(e.seat,e.direction);//当前位置设为新方向的相邻块
}//if
}//if
}//else
}while(!
StackEmpty(S));
curpos=M.start;//设定"当前位置"为"入口位置"
curstep=1;//探索第一步
//如果第一次查找无结果则再进行一次八个方向的查找,检查是否存在第一次查找不到的特殊情况
do{
if(Pass(M,curpos)){//当前位置可通过,即是未曾走到过的通道块
M.Maze[curpos.row][curpos.col]='';//留下足迹
e.direction=1;
e.order=curstep;
e.seat=curpos;
Push(S,&e);//加入路径
if(curpos.row==M.end.row&&curpos.col==M.end.col){
//到达终点(出口)
//PrintPath(maze,S);//输出路径
returnSUCCESS;
}
curpos=NextPos(curpos,1);//下一位置是当前位置的东邻
curstep++;//探索下一步
}
else{//当前位置不能通过
if(!
StackEmpty(S)){
Pop(S,&e);
while(e.direction==8&&!
StackEmpty(S)){
M.Maze[curpos.row][curpos.col]='';//标记不能通过
Pop(S,&e);//留下不能通过的标记,并退回一步
}//while
if(e.direction<8){
e.direction++;
GetTop(S,&te);
if(e.direction==4&&te.direction==2){
Pop(S,&e);
e.direction++;
}
Push(S,&e);//换下一个方向探索
curpos=NextPos(e.seat,e.direction);//当前位置设为新方向的相邻块
}//if
}//if
}//else
}while(!
StackEmpty(S));
returnFAIL;
}//MazePath
voidPrintPath(MAZEM,SqStackPath){//将迷宫及路径一起打印
if(StackEmpty(&Path)){
printf("NoPath!
\n");//路径栈为空,则提示无路径
exit(OVERFLOW);
}
printf("\nThePath:
\n");
for(row=0;rowfor(col=0;colif(SameSeat(Path,row,col)){
if((row==1&&col==1)||(row==M.length&&col==M.width))
printf("#");
else
printf(">");
num++;
p++;
}
else
printf("%c",M.Maze[row][col]);
}
printf("\n");
}
}
⑶主函数算法:
voidmain(){
MAZEM;
SqStackpath;
InitStack(&path);
SetMaze(&M);
PrintMaze(M);
MazePath(M,&path);
PrintPath(M,path);
}
⒉函数的调用关系反映了本演示程序的层次结构
main
InitStackMazePathPrintPathPrintMazePassSetMazeSameSeatNextPos
……
PushGetTopPopStackEmpty
三、调试分析
1、开始没有将M[n][m].start.end设置为MAZE型数据的下属单元,使得各个迷宫操作的函数参数十分散杂,调试时各参数关系不易把握。
2、另行设置PrintPath函数,使得终端输出更加友好,并巧妙地将迷宫以特殊、明朗的字符输出,效果更好。
3、开始出栈入栈的条件没有控制好,导致输出时不是完整路径,甚至出错。
4、选择方向时有一定策略,开始选择时按照顺时针依次读取方向,发现太耗时且效果不好,容易出现不必要的弯折走法,后来通过控制方向顺序,即第一方向为东南方,然后再东方、南方...,选取越靠近出口的方向为优先方向,因为这样的话搜索路径时自然会本着路径最短的原则向出口处行进,那么找到的路径自然是最短路径(之一)。
5、由于八个方向的特殊性,根据方向的顺序,搜索路径时仍会出现多走的情况,比如先往东再往西南,其实是可以直接往南的,因此为了避免这种情况,在入栈时还要先进行这种情况的判断,如是这种情况则出栈将前一位置方向改变再入栈。
6、为了便于找到最短路径,起初只使用了靠近出口处的五个方向,但是发现有特殊情况存在时由于不能想远离出口的方向行进而找不到路径,因此在搜索路径时进行了两次搜索,第一次使用五个靠进出口的方向搜索,找到路径时则返回SUCCESS,若未搜索到则再进行一次八个方向的搜索,即为了防止漏掉特殊情况,找到时则返回SUCCESS,由于第一搜索无结果若第二次搜索到路径也只能是特殊情况,故也应该是最短路径(之一)。
7、最大的问题是并没有按照题目要求来做,因为题目中要求用队列来存储路径,经过实验发现有很多问题难以解决,故选择了只用栈的方法来实现。
四、用户说明
⒈本程序的运行环境为windows7(64位)操作系统,执行文件为数据结构迷宫.exe;
⒉进入演示程序后,即显示对话形式的提示操作过程,
1、提出输入迷宫的大小
2、按enter键输出随机生成的迷宫
3、按enter键开始搜索路径
搜索结果:
ThePath:
输出迷宫及路径或者输出NoPath!
⒊提示输入迷宫大小后,用户输入所要处理迷宫的长row,宽col;
⒋提示输入迷宫后,用户将迷宫输入,0代表可行,1代表障碍;
⒌按任意键开始后,程序自动进行对所建迷宫的搜索,并将搜索结果;
⒍按任意键退出程序。
五、测试结果
1、无路径:
2、找到最短路径:
六、附录(源代码及注释)
#include"time.h"
#include"stdio.h"
#include"stdlib.h"
#include"conio.h"
#defineNULL0
#defineTRUE1
#defineFALSE0
#defineSUCCESS1
#defineFAIL0
#defineOK1
#defineERROR0
#defineOVERFLOW-1
#defineINFEASIBLE-2
#defineMAXLENGTH50
#defineMAXWIDTH50
#defineSTACK_INIT_SIZE100
#defineSTACKINCRENT10
//元素类型
typedefintStatus;
typedefstruct{
introw;
intcol;
}Position;//位置坐标
typedefstruct{
intorder;
Positionseat;
intdirection;
}SElemType;//步数、方向及位置
//栈定义
typedefstructlnode{
SElemType*base;
SElemType*top;//设两指针便于判断栈是否为空
intstacksize;//栈当前可使用的最大容量
}SqStack;
//迷宫定义
typedefintElemType;
typedefstructMAZE{
ElemTypeMaze[MAXLENGTH][MAXWIDTH];
intlength,width;
Positionstart,end;
}MAZE;//迷宫大小及出入口位置
//栈操作函数声明
StatusInitStack(SqStack*S);//初始化
StatusStackEmpty(SqStack*S);//判空
StatusGetTop(SqStack*s,SElemType*e);//取栈顶元素
StatusPush(SqStack*S,SElemType*e);//入栈
StatusPop(SqStack*s,SElemType*e);//出栈
//迷宫操作函数说明
voidSetMaze(MAZE*M);/*设置迷宫,随机生成*/
voidPrintMaze(MAZEM);/*输出迷宫*/
StatusPass(MAZEM,PositionCurPos);//判断当前位置是否可通
PositionNextPos(PositionCurPos,intdirectionr);//下一位置
StatusSameSeat(SqStackPath,introw,intcol);//找到迷宫中可行路径的各个位置
StatusMazePath(MAZEM,SqStack*Path);//搜索迷宫路径
voidPrintPath(MAZEM,SqStackPath);//若迷宫M存在可行路径则将该路径在迷宫中输出
//主函数
voidmain(){
MAZEM;
SqStackpath;
InitStack(&path);
SetMaze(&M);
PrintMaze(M);
MazePath(M,&path);
PrintPath(M,path);
}
//迷宫操作
voidSetMaze(MAZE*M){
intlength,width,j,k;
printf("Pleaseinputthelengthandwidth