迷宫求解实验报告.docx
《迷宫求解实验报告.docx》由会员分享,可在线阅读,更多相关《迷宫求解实验报告.docx(23页珍藏版)》请在冰豆网上搜索。
迷宫求解实验报告
《编程实训》
实验报告书
专业:
计算机科学与技术
班级:
1班
学号:
姓名:
周*
指导教师:
周**
日期:
2016年6月30日
一、需求分析…………………………………………………………………………………3
1.任务要求……………………………………………………………………………………3
2.软件功能分析………………………………………………………………………………3
3.数据准备……………………………………………………………………………………3
二、概要设计…………………………………………………………………………………3
1.功能模块图………………………………………………………………………………4
2.模块间调用关系…………………………………………………………………………4
3.主程序模块………………………………………………………………………………5
4.抽象数据类型描述…………………………………………………………………………5
三、详细设计…………………………………………………………………………………6
1.存储结构定义………………………………………………………………………………6
2.各功能模块的详细设计……………………………………………………………………7
四、实现和调试………………………………………………………………………………7
1.主要的算法………………………………………………………………………………7
2.主要问题及解决…………………………………………………………………………8
3.测试执行及结果……………………………………………………………………………8
五、改进………………………………………………………………………………………9
六、附录……………………………………………………………………………………9
1 需求分析
1.1 任务要求
以一个m*n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。
设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。
1.2 软件功能分析
设计一个迷宫,通过该程序可以找出通往出口的最短路径。
程序功能有三(1)创建迷宫;(2)求解迷宫;(3)输出迷宫的解。
1.3 数据准备
迷宫的测试数据如下:
左上角(1,1)为入口,右下角(9,8)为出口。
0
0
1
0
0
0
1
0
0
0
1
0
0
0
1
0
0
0
0
0
1
1
0
1
0
1
1
1
0
0
1
0
0
0
0
1
0
0
0
0
0
1
0
0
0
1
0
1
0
1
1
1
1
0
0
1
1
1
0
0
0
1
0
1
1
1
0
0
0
0
0
0
障碍物坐标:
13172327353638
42434447546266
68727374757881
8286889192
2概要设计
2.1 功能模块图
栈的顺序存储表示
#defineStackSize100//假定预分配的栈空间最多为100个元素
typedefcharDataType;//假定栈元素的数据类型为字符
typedefstruct{
DataTypedata[StackSize];
inttop;
}SeqStack;
基本操作的算法描述
(1)置栈空
voidInitStack(SeqStack*S)
{//将顺序栈置空
S->top=-1;
}
(2)判栈空
intStackEmpty(SeqStack*S)
{
returnS->top==-1;
}
(3)判栈满
intStackFull(SeqStack*SS)
{
returnS->top==StackSize-1;
}
(4)进栈
voidPush(S,x)
{
if(StackFull(S))
Error("Stackoverflow");//上溢,退出运行
S->data[++S->top]=x;//栈顶指针加1后将x入栈
}
(5)退栈
DataTypePop(S)
{
if(StackEmpty(S))
Error("Stackunderflow");//下溢,退出运行
returnS->data[S->top--];//栈顶元素返回后将栈顶指针减1
}
(6)取栈顶元素
DataTypeStackTop(S)
{
if(StackEmpty(S))
Error("Stackisempty");
returnS->data[S->top];
}
2.2 模块间调用关系
Stack.h中调用的base.h
#include
#include
#include
#defineTRUE1
#defineFALSE0
#defineOK1
#defineERROR0
#defineOVERFLOW-2
typedefintStatus;
2.3 主程序模块
主程序maze.c中调用的stack.h
#defineINIT_SIZE100//存储空间初始分配量
#defineINCREMENT10//存储空间分配增量
typedefstruct{//迷宫中r行c列的位置
intr;
intc;
}PostType;
typedefstruct{
intord;//当前位置在路径上的序号
PostTypeseat;//当前坐标
intdi;//往下一坐标的方向
}SElemType;//栈元素类型
typedefstruct{
SElemType*base;//栈基址,构造前销毁后为空
SElemType*top;//栈顶
intstackSize;//栈容量
}Stack;//栈类型
StatusInitStack(Stack&S){//构造空栈s
S.base=(SElemType*)malloc(INIT_SIZE*sizeof(SElemType));
if(!
S.base)
exit(OVERFLOW);//存储分配失败
S.top=S.base;
S.stackSize=INIT_SIZE;
returnOK;
}//InitStack
StatusStackEmpty(StackS){
//若s为空返回TRUE,否则返回FALSE
if(S.top==S.base)
returnTRUE;
returnFALSE;
}//StackEmpty
StatusPush(Stack&S,SElemTypee){
//插入元素e为新的栈顶元素
if(S.top-S.base>=S.stackSize){//栈满,加空间
S.base=(SElemType*)realloc(S.base,(S.stackSize+INCREMENT)*sizeof(SElemType));
if(!
S.base)
exit(OVERFLOW);//存储分配失败
S.top=S.base+S.stackSize;
S.stackSize+=INCREMENT;
}
*S.top++=e;
returnOK;
}//push
StatusPop(Stack&S,SElemType&e){//若栈不空删除栈//顶元素用e返回并返回OK,否则返回ERROR
if(S.top==S.base)
returnERROR;
e=*--S.top;
returnOK;
}//Pop
StatusDestroyStack(Stack&S){//销毁栈S,
free(S.base);
S.top=S.base;
returnOK;
}//DestroyStack
2.4 抽象数据类型描述
栈(stack)是限定仅在表尾进行插入或删除操作的线性表。
因此,对栈来说,表尾端有特殊含义,称为栈顶(top),相应的,表头端称为栈底(bottom)。
不含元素的空表称为空栈。
假设栈S=(a1,a2,…,an),则称a1为栈底元素,an为栈顶元素。
栈的修改是按后进先出的原则进行的。
因此,栈又称为后进先出(ListInFirstOut)的线性表。
在迷宫问题中,假设以栈S记录“当前路径”,则栈顶中存放的是“当前路径上最后一个通道块”。
由此,“纳入路径”的操作即为“当前位置入栈”;“从当前路径上删除前一通道块”的操作即为“出栈”。
3详细设计
3.1 存储结构定义
typedefintStatus;
#defineINIT_SIZE100//存储空间初始分配量
#defineINCREMENT10//存储空间分配增量
typedefstruct
{//迷宫中r行c列的位置
intr;
intc;
}PostType;
typedefstruct
{
intord;//当前位置在路径上的序号
PostTypeseat;//当前坐标
intdi;//往下一坐标的方向
}SElemType;
//栈元素类型
typedefstruct
{
SElemType*base;//栈基址,构造前销毁后为空
SElemType*top;//栈顶
intstackSize;//栈容量
}Stack;
//栈类型
3.2 各功能模块的详细设计
●初始化迷宫
StatusInitMaze(MazeType&maze)
●可通位置
StatusPass(MazeTypemaze,PostTypecurpos)
●标记非通路
StatusMarkPrint(MazeType&maze,PostTypecurpos)
●迷宫maze从入口start到end的通道
StatusMazePath(MazeType&maze,PostTypestart,PostTypeend)
●标记路径信息
voidPrintMaze(MazeType&maze)
4实现和调试
4.1 主要的算法
设定当前位置的初值为入口位置;
do{
若当前位置可通,则
{
将当前位置入栈; //纳入路径
若该位置是出口位置,则结束; //求得路径存放在栈中
否则切换当前位置的上方位置为新的当前位置;
}
否则
{
若栈不空且栈顶位置尚有其他方向未被探索,
则设定新的当前位置为沿着顺时针方向旋转找到的栈顶位置的下一个相邻块;
若栈不空但栈顶位置的四周均不可通,
则
{
删去栈顶位置; //后退一步,从路径中删去该通道块
若栈不空,则重新测试新的栈顶位置,
直至找到一个可通的相邻块或出栈至栈空;
}
}
}while(栈不空)
{栈空说明没有路径存在}
4.2 主要问题及解决
经过对程序的编制,调试和运行,使我更好的掌握了栈基本性质和有关迷宫问题的解决方法,熟悉了各种调用的数据类型,在调试和运行过程中使我更加的了解和熟悉程序运行的环境,提高了我对程序调试分析的能力和对错误的纠正能力。
4.3 测试执行及结果
输入数据:
当入口为(1,1)时,出口为(9,8)
用一个字符类型的二微数组表示迷宫,数组中的每个元素表示一个小方格,取值“0”(表示可以进出)或“1”(表示不可以进出)
随机产生一个9*8的迷宫,其中使用迷宫障碍坐标如下:
13172327353638
42434447546266
68727374757881
8286889192
输入过程如下图所示:
输入时(-1,-1)结束,接着输入入口参数(1,1)
然后输入出口参数(9,8),运行:
运行结果如下图所示:
图中“1”表示围墙和障碍物。
“@”表示走过但不是通路.而“0”表示最短路径。
5改进
通过不断的调试简短了程序并最终实现了功能。
第一次写的程序出现错误,找不到路径,陷入死循环。
经过多次改进,程序可以找到最短路径。
再次改进后能标出走过的但非最短的路径,有了很大的进步。
6附录
源程序代码
#include
#include
#include
#defineTRUE1
#defineFALSE0
#defineOK1
#defineERROR0
#defineOVERFLOW-2
typedefintStatus;
#defineINIT_SIZE100//存储空间初始分配量
#defineINCREMENT10//存储空间分配增量
typedefstruct
{//迷宫中r行c列的位置
intr;
intc;
}PostType;
typedefstruct
{
intord;//当前位置在路径上的序号
PostTypeseat;//当前坐标
intdi;//往下一坐标的方向
}SElemType;
//栈元素类型
typedefstruct
{
SElemType*base;//栈基址,构造前销毁后为空
SElemType*top;//栈顶
intstackSize;//栈容量
}Stack;
//栈类型
StatusInitStack(Stack&S)
{//构造空栈s
S.base=(SElemType*)malloc(INIT_SIZE*sizeof(SElemType));
if(!
S.base)
exit(OVERFLOW);//存储分配失败
S.top=S.base;
S.stackSize=INIT_SIZE;
returnOK;
}//InitStack
StatusStackEmpty(StackS)
{
//若s为空返回TRUE,否则返回FALSE
if(S.top==S.base)
returnTRUE;
returnFALSE;
}//StackEmpty
StatusPush(Stack&S,SElemTypee)
{
//插入元素e为新的栈顶元素
if(S.top-S.base>=S.stackSize)
{//栈满,加空间
S.base=(SElemType*)realloc(S.base,(S.stackSize+INCREMENT)*sizeof(SElemType));
if(!
S.base)
exit(OVERFLOW);//存储分配失败
S.top=S.base+S.stackSize;
S.stackSize+=INCREMENT;
}
*S.top++=e;
returnOK;
}//push
StatusPop(Stack&S,SElemType&e)
{//若栈不空删除栈//顶元素用e返回并返回OK,否则返回ERROR
if(S.top==S.base)
returnERROR;
e=*--S.top;
returnOK;
}//Pop
StatusDestroyStack(Stack&S)
{//销毁栈S,
free(S.base);
S.top=S.base;
returnOK;
}//DestroyStack
#defineMAXLEN10//迷宫包括外墙最大行列数目
typedefstruct
{
intr;
intc;
charadr[MAXLEN][MAXLEN];//可取'''*''@''#'
}MazeType;//迷宫类型
StatusInitMaze(MazeType&maze)
{
//初始化迷宫若成功返回TRUE,否则返回FALSE
intm,n,i,j;
printf("输入行和列数:
");
scanf("%d%d",&maze.r,&maze.c);//迷宫行和列数
for(i=0;i<=maze.c+1;i++)
{//迷宫行外墙
maze.adr[0][i]='1';
maze.adr[maze.r+1][i]='1';
}//for
for(i=0;i<=maze.r+1;i++)
{//迷宫列外墙
maze.adr[i][0]='1';
maze.adr[i][maze.c+1]='1';
}
for(i=1;i<=maze.r;i++)
for(j=1;j<=maze.c;j++)
maze.adr[i][j]='';//初始化迷宫
printf("输入障碍物坐标,以-1-1结束:
");
scanf("%d%d",&m,&n);//接收障碍的坐标
while(m!
=-1)
{
if(m>maze.r||n>maze.c)//越界
exit(ERROR);
maze.adr[m][n]='1';//迷宫障碍用'#'标记
printf("输入障碍物坐标,以-1-1结束:
");
scanf("%d%d",&m,&n);
}//while
returnOK;
}//InitMaze
StatusPass(MazeTypemaze,PostTypecurpos)
{
//当前位置可通则返回TURE,否则返回FALSE
if(maze.adr[curpos.r][curpos.c]=='')//可通
returnTRUE;
else
returnFALSE;
}//Pass
StatusFootPrint(MazeType&maze,PostTypecurpos)
{
//若走过并且可通返回TRUE,否则返回FALSE
//在返回之前销毁栈S
maze.adr[curpos.r][curpos.c]='0';//"*"表示可通
returnOK;
}//FootPrint
PostTypeNextPos(PostType&curpos,inti)
{
//指示并返回下一位置的坐标
PostTypecpos;
cpos=curpos;
switch(i)
{//1.2.3.4分别表示东,南,西,北方向
case1:
cpos.c+=1;break;
case2:
cpos.r+=1;break;
case3:
cpos.c-=1;break;
case4:
cpos.r-=1;break;
default:
exit(ERROR);
}
returncpos;
}//Nextpos
StatusMarkPrint(MazeType&maze,PostTypecurpos)
{
//曾走过但不是通路标记并返回OK
maze.adr[curpos.r][curpos.c]='@';//"@"表示曾走过但不通
returnOK;
}//MarkPrint
StatusMazePath(MazeType&maze,PostTypestart,PostTypeend)
{
//若迷宫maze存在从入口start到end的通道则求得一条存放在栈中
//并返回TRUE,否则返回FALSE
StackS;
PostTypecurpos;
intcurstep;//当前序号,1.2.3.4分别表示东,南,西,北方向
SElemTypee;
InitStack(S);
curpos=start;//设置"当前位置"为"入口位置"
curstep=1;//探索第一步
do
{
if(Pass(maze,curpos))
{//当前位置可以通过,
//即是未曾走到过的通道
FootPrint(maze,curpos);//留下足迹
e.ord=curstep;
e.seat=curpos;
e.di=1;
Push(S,e);//加入路径
if(curpos.r==end.r&&curpos.c==end.c)
if(!
DestroyStack(S))//销毁失败
exit(OVERFLOW);
else
returnTRUE;//到达出口
else
{
curpos=NextPos(curpos,1);//下一位置是当前位置的东邻
curstep++;//探索下一步
}//else
}//if
else
{//当前位置不通
if(!
StackEmpty(S))
{
Pop(S,e);
while(e.di==4&&!
StackEmpty(S))
{
MarkPrint(maze,e.seat);
Pop(S,e);//留下不能通过的标记,并退一步
}//while
if(e.di<4)
{
e.di++;//换下一个方向探索
Push(S,e);
curpos=NextPos(e.seat,e.di);//设定当前位置是该
//新方向上的相邻
}//if
}//if
}//else
}
while(!
StackEmpty(S));
if(!
DestroyStack(S))//销毁失败
exit(OVERFLOW);
else
returnFALSE;
}//MazePath
voidPrintMaze(MazeType&maze)
{//将标记路径信息的迷宫输出到终端(包括外墙)
inti,j;
printf("\n迷宫的路径(*---路径):
\n\n");
printf("");
for(i=0;i<=maze.r+1;i++)//打印列数