算法与数据结构课程设计漫步迷宫.docx
《算法与数据结构课程设计漫步迷宫.docx》由会员分享,可在线阅读,更多相关《算法与数据结构课程设计漫步迷宫.docx(22页珍藏版)》请在冰豆网上搜索。
算法与数据结构课程设计漫步迷宫
目录
一、课程设计题目3
二、问题描述3
三、基本要求3
四、设计思想3
4.1函数的功能和参数3
4.2存储结构的选择4
4.3迷宫有解无解情况的解读5
五、漫步迷宫源程序5
六、运行结果10
6.1主界面10
6.2手动生成迷宫10
6.3自动生成迷宫13
七、设计过程出现的问题和优点14
八、设计的心得体会17
《数据结构》课程设计-------漫步迷宫
一、课程设计题目:
漫步迷宫
二、问题描述:
用m行n列的m*n个正方格表示一个迷宫,其中划有斜线的方格表示不可通行,未划有斜线的方格表示通行。
请编写寻找从入口到出口的一条最短路径的程序。
三、基本要求:
1、迷宫的规则(即行数和列数),状态设置(即各方格能否通行的状态),以及入口和出口的位置,均应由输入随机确定。
2、求得的最短路径,应该以从入口到出口的路径上的各个方格的坐标的线性序列输出。
当无通路是,应该报告无路径的信息。
3、尽量采用结构化程序设计方法,要求对各个模块的功能及参数做必要的说明。
四、设计思想
4.1函数的功能和参数
函数参数
函数作用
point
Row,col,predecessor
row,col,predecessor分别代表当前位置的行坐标和列坐标,列坐标和移动到下一步的方向
creat_maze
m,n
手动输入迷宫,其中m,n分别为行列的值
present_maze
m,n
自动生成迷宫,其中m,n分别为行列的值
present_in
m,n,a,b
自动生成迷宫的入口,m,n,a,b分别为迷宫的行数、列数、入口的坐标
present_out
m,n,c,d
自动生成迷宫的出口,m,n,c,d分别为迷宫的行数、列数、出口的坐标
print_maze
m,n,a,b,c,d
显示生成的迷宫的图形,m,n,a,b,c,d分别为迷宫的行数和列数、入口坐标和出口坐标
result_maze
m,n
显示最后的迷宫最短路径的路线,m,n分别为路径的各个点的行列数坐标
enqueue
p
为队列函数,实现迷宫的各个点的存储
visit
row,col
将迷宫当前位置的前后左右四个方向上联通但没有走过的点的值改为2,row,col分别代表当前位置的行坐标和列坐标
mazepath
m,n,a,b,c,d
实现对迷宫的最短路径的回溯,m,n,a,b,c,d分别为迷宫的行数和列数、入口坐标和出口坐标
4.2存储结构的选择
在这个编写的迷宫程序中,我采用的是队列,而没有采用栈这种数据结构。
队列将迷宫的每个点都用顺序存储的方式将它存储起来,便于在需找路径是广度优先搜索。
首先是将迷宫的各个点的是否通路用0和1表示出来,形成数组,存入到maze这个数组中。
当指定一个入口时,首先判断该点是否为通路,若不为通路则直接输出“此迷宫无解”,然后再判断所处位置的前后左右的四个方向上的连通性和是否为出口,连通则记在队列中,若为出口,则停止入队列。
在要寻找迷宫路径时,从出口开始回溯查找,将在出口到入口这条路径上的点的值记为3,便于输出迷宫路径。
在这个程序中我们要寻找的是迷宫的最短路径,所以要用广度优先搜索,在用广度优先搜索时,每个点都会观察它的前后左右的连通性,每走一步便记录一下,最后走出迷宫的路径便一定是最短的。
编写此段程序所用语言为C语言。
4.3迷宫的有解和无解的情况解读:
在这个迷宫中会出现无解的情况,特别是在自动生成迷宫的时候,甚至还有自动生成迷宫的入口和出口,在自动生成时,给点的赋值为0或1,每个点连通的情况时一半一半的,这样的概率也就导致了它的无解。
无解也就说明了出口和入口不在一个连通分量上。
五、漫步迷宫源程序
#include"stdlib.h"
#include"stdio.h"
#defineN50
#defineM50
intX;
intmaze[N][M];
structpoint{
introw,col,predecessor;
}queue[512];
inthead=0,tail=0;
voidcreat_maze(intm,intn){
inti,j;
printf("\n\n");
printf("请按行输入迷宫,0表示通路,1表示障碍:
\n\n");
for(i=0;ifor(j=0;j{
printf("maze[%d][%d]:
",i,j);
scanf("%d",&maze[i][j]);
}
}
voidpresent_maze(intm,intn){
inti,j;
printf("\n迷宫自动生成中……\n\n");
system("pause");
for(i=0;ifor(j=0;jmaze[i][j]=rand()%2;
}
voidpresent_in(intm,intn,int&a,int&b)
{
printf("\n迷宫入口自动生成中……\n\n");
system("pause");
a=rand()%m;
b=rand()%n;
}
voidpresent_out(intm,intn,int&c,int&d)
{
printf("\n迷宫出口自动生成中……\n\n");
system("pause");
c=rand()%m;
d=rand()%n;
}
voidprint_maze(intm,intn,inta,intb,intc,intd){
inti,j;
printf("\n迷宫生成结果如下:
\n\n");
//printf("迷宫入口\n");
//printf("↓");
for(i=0;i{printf("\n");
for(j=0;j{if(maze[i][j]==0)printf("□");
if(maze[i][j]==1)printf("■");}
}
//printf("→迷宫出口\n");
}
voidresult_maze(intm,intn){
inti,j;
printf("迷宫通路(用&表示)如下所示:
\n\t");
for(i=0;i{printf("\n");
for(j=0;j{if(maze[i][j]==0||maze[i][j]==2)printf("□");
if(maze[i][j]==1)printf("■");
if(maze[i][j]==3)printf("&");
}
}
}
voidenqueue(structpointp){
queue[tail]=p;
tail++;
}
structpointdequeue(){
head++;
returnqueue[head-1];
}
intis_empty(){
returnhead==tail;
}
voidvisit(introw,intcol,intmaze[50][50]){
structpointvisit_point={row,col,head-1};
maze[row][col]=2;
enqueue(visit_point);
}
intmazepath(intmaze[50][50],intm,intn,inta,intb,intc,intd){
X=1;
structpointp={a,b,-1};
if(maze[p.row][p.col]==1)
{printf("\n*****************************************************\n");
printf("此迷宫无解\n\n");X=0;return0;}
maze[p.row][p.col]=2;
enqueue(p);
while(!
is_empty())
{p=dequeue();
if((p.row==c)&&(p.col==d))break;
if((p.row+1if((p.col+1if((p.col-1>=0)&&(maze[p.row][p.col-1]==0))visit(p.row,p.col-1,maze);
if((p.row-1>=0)&&(maze[p.row-1][p.col]==0))visit(p.row-1,p.col,maze);
}
if(p.row==c&&p.col==d)
{printf("\n***************************************************n");
printf("迷宫路径为:
\n");
printf("(%d,%d)\n",p.row,p.col);
maze[p.row][p.col]=3;
while(p.predecessor!
=-1)
{p=queue[p.predecessor];
printf("(%d,%d)\n",p.row,p.col);
maze[p.row][p.col]=3;
}
}
else{printf("\n************************************************\n");
printf("此迷宫无解!
\n\n");X=0;}
return0;
}
voidmain()
{inti,m,n,a,b,c,d,j,cycle=0;
while(cycle!
=(-1))
{
printf("*********************************************************************\n");
printf("2011-2012学年第二学期数据结构课程设计\n");
printf("------漫步迷宫\n");
printf("开发员:
曾祥柯\n");
printf("班级:
10计算本1班\n");
printf("学号:
1015023129\n");
printf("欢迎进入漫步迷宫\n");
printf("*********************************************************************\n");
printf("手动生成迷宫请按:
1\n");
printf("自动生成迷宫请按:
2\n");
printf("退出漫步迷宫请按:
3\n\n");
printf("*********************************************************************\n");
printf("\n");
printf("请选择你的操作:
\n");
scanf("%d",&i);
switch(i)
{case1:
printf("\n请输入行数:
");scanf("%d",&m);
printf("\n");
printf("请输入列数:
");scanf("%d",&n);
while((m<=0||m>50)||(n<=0||n>50))
{printf("\n抱歉,你输入的行列数超出预设范围(0-50,0-50),请重新输入:
\n\n");
printf("请输入行数:
");scanf("%d",&m);
printf("\n");
printf("请输入列数:
");scanf("%d",&n);
}
creat_maze(m,n);
print_maze(m,n,a,b,c,d);
printf("\n");
printf("*********************************************************************\n");
printf("手动输入迷宫入口请按:
1\n");
printf("自动生成迷宫入口请按:
2\n");
printf("*********************************************************************\n");
printf("\n");
printf("请选择你的操作:
\n");
scanf("%d",&j);
switch(j)
{case1:
printf("请输入入口坐标:
");scanf("%d,%d",&a,&b);
while((a<0||a>m-1)||(b<0||b>n-1))
{printf("\n抱歉,你输入的行列数超出预设范围(0-%d,0-%d),请重新输入:
\n\n",m-1,n-1);
printf("请输入入口坐标:
");scanf("%d,%d",&a,&b);}break;
case2:
present_in(m,n,a,b);break;
}
printf("\n");
printf("请输入出口坐标:
");scanf("%d,%d",&c,&d);
while((c<0||c>m-1)||(d<0||d>n-1))
{printf("\n抱歉,你输入的行列数超出预设范围(0-%d,0-%d),请重新输入:
\n\n",m-1,n-1);
printf("请输入入口坐标:
");scanf("%d,%d",&c,&d);
}
print_maze(m,n,a,b,c,d);
mazepath(maze,m,n,a,b,c,d);
if(X!
=0)result_maze(m,n);
printf("\n\nPressEnterContiue!
\n");getchar();while(getchar()!
='\n');break;
case2:
printf("\n请输入行数:
");scanf("%d",&m);
printf("\n");
printf("请输入列数:
");scanf("%d",&n);
while((m<=0||m>50)||(n<=0||n>50))
{printf("\n抱歉,你输入的行列数超出预设范围(0-50,0-50),请重新输入:
\n\n");
printf("请输入行数:
");scanf("%d",&m);
printf("\n");
printf("请输入列数:
");scanf("%d",&n);
}
present_maze(m,n);
print_maze(m,n,a,b,c,d);
printf("\n");
printf("请输入入口坐标:
");scanf("%d,%d",&a,&b);
printf("\n");
printf("请输入出口坐标:
");scanf("%d,%d",&c,&d);
mazepath(maze,m,n,a,b,c,d);
if(X!
=0)result_maze(m,n);
printf("\n\nPressEnterContiue!
\n");getchar();while(getchar()!
='\n');break;
case3:
cycle=(-1);break;
default:
printf("\n");printf("你的输入有误!
\n");
printf("\nPressEnterContiue!
\n");getchar();while(getchar()!
='\n');break;
}
}
}
六、运行结果
将该程序的各个功能都运行了结果,分为主界面、手动建立迷宫、自动生成迷宫、自动生成入口等模块。
主界面:
手动生成迷宫(老师所给迷宫):
此迷宫的图解和路线可写为:
|0111111111|
|0100100011|
|0001101001|入口坐标为[0,0]
A.maze=|0110001101|
|0000100001|出口坐标为[5,9]
|1111111100|
则输出的最短路径应该是:
[5,9]--[5,8]ß--[4,8]ß--[4,7]ß--[4,6]
--[4,5]--[3,5]--[3,4]--[3,3]--[4,3]
--[4,2]--[4,1]--[4,0]--[3,0]--[2,0]
--[1,0]--[0,0]
手动生成迷宫(自己编写的迷宫)且自动生成迷宫入口:
自动生成迷宫(无解的情况):
自动生成迷宫(有解的情况):
七、设计过程中出现的问题及优点
1、这段程序为网上下载而来,刚开始时程序有很多版块都不够完整,没有欢迎界面,于是在主程序中做了界面的输出。
2、在程序运行中还有一个问题是刚开始时是把迷宫的入口和出口的坐标给出后才显示原始的迷宫图,这样在自动生成迷宫时很容易出现无解的情况,也无法很好的验证自动生成迷宫这一模块的正确性。
于是将原始迷宫的输出函数print_maze(m,n,a,b,c,d)提前调用了,解决了这一问题。
3、刚拿到这个程序时,它不能很好的对迷宫的大小超出范围进行报错功能,这是因为没有对输入的行数列数与它的最大值进行比较,在加了
while((m<=0||m>50)||(n<=0||n>50))后就解决了这个问题。
4、做这个迷宫程序最主要的便是在找寻路径时如何表示是路径上的点,我采用的方法是将这个点的值赋值为3表示访问过,将这个点的值赋值为2表示为通路但不在此路径上。
5、在此段程序中我并没有采用老师所说的加围墙的方法,这样就减少了程序的空间复杂度,但增加了时间复杂度。
6、这个程序有个闪光点就是可以自动生成迷宫、出口和入口,而自动生成所需进行的运算方法便是:
maze[i][j]=rand()%2,通过除2取余的方法将点的值赋值为0或1。
通过这个运算,我知道了要想随机产生X到Y的数可以讲语句写为:
k=rand()%(Y-X+1)+X,这就是学习时的举一反三。
7、该程序还有个优点便是能够把迷宫的最短路径用图形直接的显示出来,也让我们不必去对着路径重新画图。
8、在自动生成迷宫后马上将其图形输出出来,便于我们确定它的入口和出口,也就减少了迷宫无解的概率。
9、这个迷宫的大小我设定的是行列数各50,而屏幕只能装下大概30*30的数,当我们要创建大小为50*50的迷宫时就会出现迷宫输出不完全的情况,反映出来的图形如下:
10、现在这个程序还是存在一些问题,在自动生成迷宫时他便不能在自动生成入口出口,这个是需要完善的,但如果都是自动生成的会造成的后果便是迷宫无解的情况概率会很大,运行时的显示如下:
11、还有个待解决的问题便是在手动输入迷宫时,只能自动生成入口而不能自动生成出口,运行情况如下:
12、这个程序后来自己还有一个想法就是把自己以前手动创建的迷宫按创建者意见保存下来,以便下回用同一个迷宫时减少输入的麻烦,但这个功能没有实现。
这个功能需要实现文件的读取。
同时可以增加在一次游戏时多次输入出口和入口,提高一个迷宫的利用率。
八、设计的心得体会
刚开始拿到这个课程设计的题目的时候有点手足无措,因为不知道从哪开始下手,也不知道到底用什么数据结构比较好,后来老师跟我们花了一节课进行讲解,自己查找了一些资料才开始了有了一些概念,通过这次课程设计,我了解到了做队列的算法和广度优先搜索的方法,也更加熟悉了C语言。
由于能力有限,有很多自己想要的功能都没能实现,在这个时候自己也感到了十分的无奈,所以自己要多看点书,多学习才能让自己编写程序时更顺畅。
这个课程设计让我也更加懂得了做事之前的准备工作的重要性,还有就是学数据结构最重要的便是能读懂源程序和了解它的思路,对于写程序我还需要很多的锻炼才能达到一定的水平。
做任何事情都是一步一步来完善的,不应急于求成。