数据结构课程设计迷宫问题.docx
《数据结构课程设计迷宫问题.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计迷宫问题.docx(24页珍藏版)》请在冰豆网上搜索。
数据结构课程设计迷宫问题
数据结构课程设计
课程名称:
数据结构
题目:
迷宫设计
系别:
软件学院
专业:
移动设备应用开发
班级:
15级移动1班
姓名:
黄国峰
学期:
2016-2017第一学期
指导教师:
李博
时间:
2016年12月
第一部分需求分析
第二部分详细设计
第三部分调试分析
第四部分用户手册
第五部分测试结果
第六部分附录
第七部分参考文献
一、需求分析
1、对于给定的一个迷宫,给出一个出口和入口,找一条从入口到出口的通路,并把这条通路显示出来;如果没有找到这样的通路给出没有这样通路的信息。
2、可以用一个m×n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。
设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。
3、编写一个求解迷宫的非递归程序。
求得的通路以三元组(i,j,d)的形式输出,其中:
(i,j)指示迷宫中的一个坐标,d表示走到下一坐标的方向。
4、手动设置迷宫是任意给定的,所以程序要能够对给定的迷宫生成对应的矩阵表示,所以程序的输入包括了矩阵的行数、列数、迷宫内墙的个数、迷宫内墙的坐标、所求的通路的入口坐标、出口坐标。
5、自动生成的迷宫原理很简单,因为0和1分别代表通道和障碍物,所以只需要随机生成0和1然后再给最外围都赋值为1,就形成了新的迷宫。
二、详细设计
1、计算机解迷宫通常用的是“穷举求解“方法,即从人口出发,顺着某一个方向进行探索,若能走通,则继续往前进;否则沿着原路退回,换一个方向继续探索,直至出口位置,求得一条通路。
假如所有可能的通路都探索到而未能到达出口,则所设定的迷宫没有通路。
可以二维数组存储迷宫数据,通常设定入口点的下标为(1,1),出口点的下标为(n,n)。
为处理方便起见,可在迷宫的四周加一圈障碍。
对于迷宫中任一位置,均可约定有东、南、西、北四个方向可通。
2、如果在某个位置上四个方向都走不通的话,就退回到前一个位置,换一个方向再试,如果这个位置已经没有方向可试了就再退一步,如果所有已经走过的位置的四个方向都试探过了,一直退到起始点都没有走通,那就说明这个迷宫根本不通。
3、所谓"走不通"不单是指遇到"墙挡路",还有"已经走过的路不能重复走第二次",它包括"曾经走过而没有走通的路"。
显然为了保证在任何位置上都能沿原路退回,需要用一个"后进先出"的结构即栈来保存从入口到当前位置的路径。
并且在走出出口之后,栈中保存的正是一条从入口到出口的路径。
4、若当前位置“可通”,则纳入“当前路径”,并继续朝“下一位置”探索;若当前位置“不可通”,则应顺着“来的方向”退回到“前一通道块”,然后朝着除“来向”之外的其他方向继续探索;若该通道块的四周四个方块均“不可通”,则应从“当前路径”上删除该通道块。
所谓“下一位置”指的是“当前位置”四周四个方向(东、南、西、北)上相邻的方块。
假设以栈S记录“当前路径”,则栈顶中存放的是“当前路径上最后一个通道块”。
由此,“纳入路径”的操作即为“当前位置入栈”;“从当前路径上删除前一通道块”的操作即为“出栈”。
5、找通路的程序的关键部分可以表示如下:
do{
若当前位置可通,
则{
将当前位置插入栈顶; //纳入路径
若该位置是出口位置,则算法结束;
//此时栈中存放的是一条从入口位置到出口位置的路径
否则切换当前位置的东邻方块为新的当前位置;
}
否则
{
若栈不空且栈顶位置尚有其他方向未被探索,
则设定新的当前位置为:
沿顺时针方向旋转找到的栈顶位置的下一相邻块;
若栈不空但栈顶位置的四周均不可通,
则{删去栈顶位置; //从路径中删去该通道块
若栈不空,则重新测试新的栈顶位置,
直至找到一个可通的相邻块或出栈至栈空;
}
}
}while(栈不空);
6、程序中用的数据结构解析:
①程序中用了顺序栈保存当前找到的路径,当前位置不可通时,可以出栈,退回到前一个位置再继续探索通路,栈的定义如下:
structSqStack
{
SElemType*base;//在栈构造之前和销毁之后,base的值为NULL
SElemType*top;//栈顶指针
intstacksize;//当前已分配的存储空间,以元素为单位
};//顺序栈
②栈中元素的类型结构
程序中先定义了一个表示坐标的类型结构:
structPosType//迷宫坐标位置类型
{
intx;//行值
inty;//列值
};
栈中元素的类型结构如下:
structSElemType//栈的元素类型
{
intord;//通道块在路径上的"序号"
PosTypeseat;//通道块在迷宫中的"坐标位置"
intdi;//从此通道块走向下一通道块的"方向"(0~3表示东~北)
};
7、主函数的流程图
三、调试分析
1、对于程序的设计由简单到复杂,先设计一个整体的轮廓然后再慢慢的增加程序的功能,这样能够有效的减少错误,功能慢慢的增加,在前一步的程序运行通过之后再继续增加功能,这样在检查错误的时候比较有目的性,提高写程序的效率。
2、对于程序中的错误,如果遇到说变量没有定义或者数据结构没定义的错误,可能是由于你在定义这种数据结构的变量时数据结构还没有定义,也就是说在定义此数据结构的变量的语句要放在声明这种结构体之后。
3、在写程序时要注意printf和scanf语句的格式,格式不对会得不到你想要的结果。
4、写程序时一定要瞻前顾后,前后一致,包括名称、数据类型等等。
四、用户手册
在使用程序时严格按照程序给出的提示一步一步来,下面给出程序正常执行的步骤:
1、程序会提示“请输入迷宫的行数,列数(包括外墙):
”,这时就需要输入表示迷宫的二维数组的行数和列数,需要注意的是由于我们在迷宫周围加了一道墙,所以要输入的行列数要比实际表示迷宫的行列数多两行两列。
2、程序提示“请输入迷宫内墙单元数:
”,此时需要输入迷宫中墙的数目。
3、程序提示“请依次输入迷宫内墙每个单元的行数,列数:
”,此时要输入迷宫中所有墙的坐标,我们用数组中的一个元素来表示墙。
4、在输入了迷宫所有内墙的坐标后,程序会显示出迷宫的结构,然后程序会提示“请输入起点的行数,列数:
”,此时需要输入所求通路的起点坐标。
5、程序提示“请输入终点的行数,列数:
”,此时需要输入所求通路的终点的坐标。
6、终点坐标输入完毕之后,程序会显示出两种运行的结果,一种是输出了迷宫的结构,此时迷宫中已包含了所找的通路,用连续的数字表示出了通路在迷宫中是如何走的,此时迷宫中的-1表示找通路时走过的单元但是通路不通。
注意:
再输入内墙单元的坐标是一定要细心,不要错输,也不要漏输。
否则程序会出错。
五、测试结果
迷宫的测试数据如下:
左上角(1,1)为入口,右下角(9,8)为出口。
12345678
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
程序的测试结果为:
1、程序的开始界面
六、附录(附有完整的源程序)
源程序如下:
#include
#include
#defineTRUE1
#defineFALSE0
#defineOK1
#defineERROR0
#defineOVERFLOW-2
#defineSTACKINCREMENT10
#defineSTACK_INIT_SIZE100//初始长度
typedefintStatus;
structPosType//坐标竖直为x,横为y
{
intx;
inty;
};
structSElemType
{
intord;//序号1,2,3,4,5,6....路径的序号
PosTypeseat;//坐标
intdi;//移动方向:
上下左右
};
structSqStack
{
SElemType*base;
SElemType*top;
intstacksize;
};
SqStackS;
#defineMAXLENGTH30
typedefintMazeType[MAXLENGTH][MAXLENGTH];//将数组做成地图。
MazeTypem;//宏定义,定义一个数组地图
intcurstep=2;//curstep代表的是足迹,走过的路
StatusInitStack(SqStack&S)
{
S.base=(SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElemType));//开空间,栈底是表头
if(!
S.base)exit(OVERFLOW);//检查是否开辟成功
S.top=S.base;//设为空栈
S.stacksize=STACK_INIT_SIZE;//设置长度
returnOK;
}
StatusPop(SqStack&S,SElemType&e)//得到栈顶元素
{
if(S.base==S.top)returnERROR;//检查是否为空栈,若为空则没有栈顶
e=*--S.top;//栈的特殊存储方式
returnOK;
}
StatusStackEmpty(SqStack&S)//判断是否为空
{
if(!
S.base)returnERROR;
if(S.base==S.top)returnTRUE;//为空
elsereturnFALSE;
}
StatusPush(SqStack&S,SElemTypee)//进栈
{
if(S.top-S.base>=S.stacksize)//栈不满
{
S.base=(SElemType*)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(SElemType));//开空间
if(!
S.base)exit(OVERFLOW);//检查是否开空间成功
S.top=S.base+S.stacksize;
S.stacksize+=STACKINCREMENT;
}
*S.top++=e;//压进栈里面
returnOK;
}
StatusPass(PosTypea)//传参传的是当前位置的坐标
{//检查当前位置是墙还是通道
if(m[a.x][a.y]==0)
{
returnOK;
}
else
{
returnERROR;
}
}
StatusFootPrint(PosTypea)//对已经走过的路做成标记1,2,3,4.。
。
{
m[a.x][a.y]=curstep;
}
PosTypeNextPos(PosTypec,intdi)//0-3上下左右
{
//作用是移动一个位置,所以需要传进来位置,移动方向,毕竟位移量已经确定为1
PosTypedirec[4]={{-1,0},{1,0},{0,-1},{0,1}};//上下左右
c.x+=direc[di].x;
c.y+=direc[di].y;
returnc;
}
voidMarkPrint(PosTypea)//走不通
{
m[a.x][a.y]=-1;//此路不通
}
voidPrint(intx,inty)//迷宫的输出
{
inti,j;
for(i=0;i{
for(j=0;j{
if(m[i][j]==1)
printf("■");
else
printf("匚");
}
printf("\n");
}
}
voidPrint1(intx,inty)//有通路的迷宫的输出
{
inti,j;
for(i=0;i{
for(j=0;j{
if(m[i][j]==1)
{
printf("■");
}
elseif(m[i][j]==-1||m[i][j]==0)
{
printf("匚");
}
elseif(m[i][j]>=2)
{
printf("☆");
}
}
printf("\n");
}
}
StatusMazePath(PosTypestart,PosTypeend)//找通路
{
InitStack(S);//保存可以走的路径
SElemTypee;
PosTypecurpos=start;//curpos是指当前位置,将开始位置设为当前位置
do
{
if(Pass(curpos))//如果当前位置的序号为0,即此位置不是迷宫中的墙即为能走的路。
{
FootPrint(curpos);//留下标记
e.ord=curstep;//输出的时候的1,2,3,4,5
e.seat.x=curpos.x;
e.seat.y=curpos.y;//将当前位置信息存入e中
e.di=0;
Push(S,e);//将这一步记录,压进栈中
curstep++;//再走一步和ord一个性质,路径的步数
if(curpos.x==end.x&&curpos.y==end.y)returnTRUE;//如果已经是出口就完成栈的记录
curpos=NextPos(curpos,e.di);//否则就走一步
}
else//如果当前位置是走过得意思就是它的序号不是0
{
if(!
StackEmpty(S))//判断栈是不是空,不是空就后退到上一步
{
Pop(S,e);//后退到上一步
curstep--;
while(e.di==3&&!
StackEmpty(S))//后退直到找到能走的路
{
MarkPrint(e.seat);
Pop(S,e);
curstep--;
}
if(e.di<3)//0—3代表上下左右
{
e.di++;
Push(S,e);
curstep++;
curpos=NextPos(e.seat,e.di);//下一步怎么移动
}
}
}
}while(!
StackEmpty(S));
returnFALSE;
}
voidAuto_maze(intx,inty)
{
inti,j;
printf("\n迷宫生成中……\n\n");
system("pause");
for(i=0;ifor(j=0;jm[i][j]=rand()%2;
}
voidGenerateMaze(intx,inty)//生成迷宫地图
{
inti,j;
intx1,y1;//障碍物坐标
for(i=0;i{
m[0][i]=1;
m[x-1][i]=1;
}
for(j=0;j{
m[j][0]=1;
m[j][y-1]=1;
}
for(i=1;i{
for(j=1;j{
m[i][j]=0;
}
}
printf("输入迷宫里面阻碍物的个数:
");
scanf("%d",&j);
printf("请输入迷宫中障碍物坐标:
\n");
for(i=0;i{
scanf("%d%d",&x1,&y1);
m[x1][y1]=1;
}
printf("************************************迷宫图**************************************\n");
Print(x,y);
printf("************************************迷宫图**************************************\n");
}
voidMovingdirection(SElemTypea)//用来显示迷宫通路怎么走的
{
switch(a.di)
{
case0:
printf("%d%3d↑\n",a.seat.x,a.seat.y);
break;
case1:
printf("%d%3d↓\n",a.seat.x,a.seat.y);
break;
case2:
printf("%d%3d←\n",a.seat.x,a.seat.y);
break;
case3:
printf("%d%3d→\n",a.seat.x,a.seat.y);
break;
}
}
voidMazePathway(PosTypebegin,PosTypeend,intx,inty)//显示迷宫通路图
{
SElemTypea;
SqStackT;
InitStack(T);
if(MazePath(begin,end))
{
printf("迷宫通路如下图所示:
\n");
Print1(x,y);
while(!
StackEmpty(S))
{
Pop(S,a);
Push(T,a);
}
printf("找到的路径用坐标表示如下:
\n");
while(!
StackEmpty(T))
{
Pop(T,a);
Movingdirection(a);
}
}
else
printf("迷宫中没有出路。
\n");
}
intmain()
{
PosTypebegin,end;
intx,y;
intn;
inti,j;
while
(1)
{
printf("*****************1.手动输入。
*****************\n");
printf("*****************2.自动生成。
*****************\n");
printf("*****************3.退出。
*****************\n");
printf("请输入:
");
scanf("%d",&n);
system("CLS");
switch(n)
{
case1:
printf("请输入迷宫的宽和长:
");
scanf("%d%d",&x,&y);
GenerateMaze(x,y);
printf("请输入起点的坐标:
");
scanf("%d%d",&begin.x,&begin.y);
printf("请输入终点的坐标:
");
scanf("%d%d",&end.x,&end.y);
MazePathway(begin,end,x,y);
break;
case2:
printf("请输入迷宫的宽和长:
");
scanf("%d%d",&x,&y);
Auto_maze(x,y);
for(i=0;i{
m[0][i]=1;
m[x-1][i]=1;
}
for(j=0;j{
m[j][0]=1;
m[j][y-1]=1;
}
Print(x,y);
printf("请输入起点的坐标:
");
scanf("%d%d",&begin.x,&begin.y);
printf("请输入终点的坐标:
");
scanf("%d%d",&end.x,&end.y);
MazePathway(begin,end,x,y);
break;
case3:
exit(-1);
}
}
return0;
}
七、参考文献
1、《数据结构(C语言版)》严蔚敏吴伟民编著清华大学出版社
2、讲课所用课件等等
欢迎您的下载,
资料仅供参考!
致力为企业和个人提供合同协议,策划案计划书,学习课件等等
打造全网一站式需求