迷宫实验报告资料.doc
- 文档编号:359999
- 上传时间:2023-04-29
- 格式:DOC
- 页数:19
- 大小:159.21KB
迷宫实验报告资料.doc
《迷宫实验报告资料.doc》由会员分享,可在线阅读,更多相关《迷宫实验报告资料.doc(19页珍藏版)》请在冰点文库上搜索。
一、实验内容
3、迷宫问题。
假设迷宫由m行n列构成,有一个出口和一个入口,入口坐标为(1,1),出口坐标为(m,n),试设计并验证以下算法:
找出一条从入口通往出口的路径,或报告一个“无法通过”的信息。
(1)用C语言实现顺序存储队列上的基本操作,然后利用该队列的基本操作找出迷宫的一条最短路径。
(2)设计一个二维数组MAZE[m+2][n+2]表示迷宫,数组元素为0表示该位置可以通过,数组元素为1表示该位置不可以通行。
MAZE[1][1]、MAZE[m][n]分别为迷宫的入口和出口。
(3)输入迷宫的大小m行和n列,动态生成二维数组;由随机数产生0或1,建立迷宫,注意m*n的迷宫需要进行扩展,扩展部分的元素设置为1,相当于在迷宫周围布上一圈不准通过的墙。
(4)要求输出模拟迷宫的二维数组;若存在最短路径,则有出口回溯到入口(出队列并利用栈实现),再打印从入口到出口的这条路径,例如(1,1),......,(i,j),......,(m,n);若没有路径,则打印“Nopath”。
(5)迷宫的任一位置(i,j)上均有八个可移动的方向,用二维数组Direction存放八个方向的位置偏移量。
Direction[8][2]={{0,1},{1,1},{0,-1},{-1,-1},{1,-1},{1,0},{-1,0},{-1,1}};
(6)为避免出现原地踏步的情况需要标志已经通过的位置,采用一个标志数组MARK[m+2][n+2],初值均为0,在寻找路径的过程中,若通过了位置(i,j),则将MARK[i][j]置为1。
(7)为了记录查找过程中到达位置(i,j)及首次到达(i,j)的前一位置(i_pre,j_pre),需要记住前一位置(i_pre,j_pre)在队列中的序号pre,即队列中数据元素应该是一个三元组(i,j,pre)。
(8)搜索过程简单下:
将入口MAZE[1][1]作为第一个出发点,依次在八个方向上搜索可通行的位置,将可通行位置(i,j,pre)入队,形成第一层新的出发点,然后依次出队,即对第一层中各个位置分别搜索它所在八个方向上的可通行位置,形成第二层新的出发点,...,如此进行下去,直至达到出口MAZE[m][n]或者迷宫所有位置都搜索完毕为止。
二、实验过程及结果
一、需求分析
1、用栈的基本操作完成迷宫问题的求解,其中栈的基本操作作为一个独立的模块存在。
2、以二维数组M[m+2][n+2]表示迷宫,M[i][j]表示迷宫中相应(i,j)位置的通行状态(0:
表示可以通行,1:
表示有墙,不可通行),完成迷宫的抽象数据类型,包括出口、入口位置等。
3、用户从屏幕上输入迷宫,从键盘输入迷宫的大小,即迷宫的长和宽(由于控制台大小限制,输入的长宽需在50以下),完成对应迷宫的初始化。
根据键盘输入的迷宫规格随机生成大小相同的迷宫,产生方块的地方为墙,无方块的地方可通过,如下例所示:
如下所示:
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={
width={
基本操作:
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;k M->Maze[0][k]=1; for(j=0;j M->Maze[j][0]=1; for(j=0;j M->Maze[j][width+1]=1; for(k=0;k M->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;row for(col=0;col if((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(p if(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;row for(col=0;col if(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: 输出迷宫及路径或者输出NoP
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 迷宫 实验 报告 资料
![提示](https://static.bingdoc.com/images/bang_tan.gif)