迷宫问题算法与数据结构课程设计报告.docx
《迷宫问题算法与数据结构课程设计报告.docx》由会员分享,可在线阅读,更多相关《迷宫问题算法与数据结构课程设计报告.docx(20页珍藏版)》请在冰豆网上搜索。
迷宫问题算法与数据结构课程设计报告
摘要
在现实生活中,会遇到很多很多关于迷宫这样很复杂、很难解决的问题的问题。
如果人工去解决这些问题,会很麻烦,花很长的时间,甚至无法解决。
假设用计算机去解决,可以通过手动生成迷宫,也可以通过计算机随机的产生迷宫,最终退出。
而且可以很快的求解迷宫,找到从入口到出口的通路,或者当没有通路时,得出没有通路的结论。
找出通路之后,会显示出通路路经,而且以图示的方式显示出通路,这样会使人一目了然的看清此迷宫的通路。
迷宫是一个矩形区域,可以使用二维数组表示迷宫,这样迷宫的每一个位置都可以用其行列号来唯一指定,但是二维数组不能动态定义其大小,我们可以考虑先定义一个较大的二维数组maze[M+2][N+2],然后用它的前m行n列来存放元素,即可得到一个m×n的二维数组,这样(0,0)表示迷宫入口位置,(m-1,n-1)表示迷宫出口位置。
关键词:
迷宫;通路;二维数组;路径
前言
随着社会经济的开展,信息化程度的不断深入,传统的人工求解迷宫问题已不能满足生活的需要。
近几年,随着迷宫问题越来越复杂、科技也越来越兴旺,人们逐渐的开场用计算机求解迷宫问题。
迷宫问题很复杂,但是人们又不得不去研究这个问题,因为人们的生活中需要它,离不开它。
在迷宫路径的搜索过程中,首先从迷宫的入口开场,如果该位置就是迷宫出口,那么已经找到了一条路径,搜索工作完毕。
否那么搜索其上、下、左、右位置是否是障碍,假设不是障碍,就移动到该位置,然后再从该位置开场搜索通往出口的路径;假设是障碍就选择另一个相邻的位置,并从它开场搜索路径。
为防止搜索重复出现,那么将已搜索过的位置标记为2,同时保存搜索痕迹,在考虑进入下一个位置搜索之前,将当前位置保存在一个队列中,如果所有相邻的非障碍位置均被搜索过,且未找到通往出口的路径,那么说明不存在从入口到出口的路径。
这实现的是广度优先遍历的算法,如果找到路径,那么为最短路径。
正文
1.采用类c语言定义相关的数据类型
节点类型和指针类型
迷宫矩阵类型:
intmaze[M+2][N+2];为方便操作使其为全局变量
迷宫中节点类型及队列类型:
structpoint{introw,col,predecessor}que[512]
2.各模块的伪码算法
1、迷宫的操作
(1)手动生成迷宫
voidshoudong_maze(intm,intn)
{定义i,j为循环变量
for(i<=m)
for(j<=n)
输入maze[i][j]的值
}
(2)自动生成迷宫
voidzidong_maze(intm,intn)
{定义i,j为循环变量
for(i<=m)
for(j<=n)
maze[i][j]=rand()%2//由于rand()产生的随机数是从0到
RAND_MAX,RAND_MAX是定义在stdlib.h中的,其值至少为32767),要产生从
X到Y的数,只需要这样写:
k=rand()%(Y-X+1)+X;
}
(3)打印迷宫图形
voidprint_maze(intm,intn)
{用i,j循环变量,将maze[i][j]输出□、■}
(4)打印迷宫路径
voidresult_maze(intm,intn)
{用i,j循环变量,将maze[i][j]输出□、■、☆}
(5)搜索迷宫路径
①迷宫中队列入队操作
voidenqueue(structpointp)
{将p放入队尾,tail++}
②迷宫中队列出队操作
structpointdequeue(structpointp)
{head++,返回que[head-1]}
③判断队列是否为空
intis_empty()
{返回head==tail的值,当队列为空时,返回0}
④访问迷宫矩阵中节点
voidvisit(introw,intcol,intmaze[41][41])
{建立新的队列节点visit_point,将其值分别赋为row,col,head-1,maze[row][col]=2,表示该节点以被访问过;调用enqueue(visit_point),将该节点入队}
⑤路径求解
voidmgpath(intmaze[41][41],intm,intn)
{先定义入口节点为structpointp={0,0,-1},从maze[0][0]开场访问。
如果入口处即为障碍,那么此迷宫无解,返回0,程序完毕。
否那么访问入口节点,将入口节点标记为访问过maze[p.row][p.col]=2,调用函数enqueue(p)将该节点入队。
判断队列是否为空,当队列不为空时,那么运行以下操作:
{调用dequeue()函数,将队头元素返回给p,
如果p.row==m-1且p.col==n-1,即到达出口节点,即找到了路径,完毕
如果p.col+1如果p.col-1>0且maze[p.row][p.col-1]==0,说明未到迷宫左边界,且其左方有通路,那么visit(p.row,p.col-1,maze),将左方节点入队标记已访问
如果p.row-1>0且maze[p.row-1][p.col]==0,说明未到迷宫上边界,且其上方有通路,那么visit(p.row,p.col+1,maze),将上方节点入队标记已访问
}
访问到出口(找到路径)即p.row==m-1且p.col==n-1,那么逆序将路径标记为3即maze[p.row][p.col]==3;
while(p.predecessor!
=-1)
{p=queue[p.predecessor];maze[p.row][p.col]==3;}
最后将路径图形打印出来。
2.菜单项选择择
while(cycle!
=(-1))
☆手动生成迷宫请按:
1
☆自动生成迷宫请按:
2
☆退出请按:
3
scanf("%d",&i);
switch(i)
{case1:
请输入行列数(如果超出预设围那么提示重新输入)
shoudong_maze(m,n);
print_maze(m,n);
mgpath(maze,m,n);
if(X!
=0)result_maze(m,n);
case2:
请输入行列数(如果超出预设围那么提示重新输入)
zidong_maze(m,n);
print_maze(m,n);
mgpath(maze,m,n);
if(X!
=0)result_maze(m,n);
case3:
cycle=(-1);break;
}
3.搜索算法流程图
4.调试分析
a、调试中遇到的问题及对问题的解决方法
在调试过程中,刚开场系统自动生成的迷宫并不是随机的,而是每次生成的都一样;求解时,不能正确的得到结果,有时还会求错;输出的路径是乱的,而不是按顺序显示。
出现上述问题之后,经过和同学的探讨研究,重写随机函数、修改语句、调换语句的位置等一次一次的试验,最终问题才得以解决。
在调试过程中,首先使用的是栈进展存储,但是产生的路径是多条或不是最短路径,所以通过算法比拟,改用此算法
b、算法的时间复杂度和空间复杂度
该算法的运行时间和使用系统栈所占有的存储空间与迷宫的大小成正比,迷宫长为m,宽为n,在最好情况下的时间和空间复杂度均为O〔m+n〕,在最差情况下均为O〔m*n〕,平均情况在它们之间
5.测试结果
进入系统主菜单:
选择1,即手动生成迷宫,及生成后有通路的求解结果:
选择2,系统自动生成迷宫,此迷宫无通路:
选择2,系统自动生成迷宫,生成的有解迷宫的解:
选择3,退出系统:
6.源程序〔带注释〕
#include"stdlib.h"
#include"stdio.h"
#defineN39
#defineM39
intX;
intmaze[N+2][M+2];
structpoint{
introw,col,predecessor;
}queue[512];
inthead=0,tail=0;
voidshoudong_maze(intm,intn){//手动生成迷宫
inti,j;
printf("\n\n");
printf("请按行输入迷宫,0表示通路,1表示障碍:
\n\n");
for(i=0;ifor(j=0;jscanf("%d",&maze[i][j]);
}
voidzidong_maze(intm,intn){//自动生成迷宫
inti,j;
printf("\n迷宫生成中……\n\n");
system("pause");
for(i=0;ifor(j=0;jmaze[i][j]=rand()%2;//自动生成迷宫的随机函数
//由于rand()产生的随机数是从0到RAND_MAX
//RAND_MAX是定义在stdlib.h中的,其值至少为32767)
//要产生从X到Y的数,只需要这样写:
k=rand()%(Y-X+1)+X;
}
voidprint_maze(intm,intn){//打印生成的迷宫
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[41][41]){
structpointvisit_point={row,col,head-1};
maze[row][col]=2;
enqueue(visit_point);
}
intmgpath(intmaze[41][41],intm,intn){
X=1;
structpointp={0,0,-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==m-1)&&(p.col==n-1))break;
if((p.col+1if((p.row+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==m-1&&p.col==n-1)
{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,cycle=0;
while(cycle!
=(-1))//主菜单
{
printf("*************************************************************\n");printf("欢送进入迷宫求解系统\n");
printf("设计者:
兰理工计算机4班永刚\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>39)||(n<=0||n>39))
{printf("\n抱歉,你输入的行列数超出预设围(0-39,0-39),请重新输入:
\n\n");
printf("请输入行数:
");scanf("%d",&m);
printf("\n");
printf("请输入列数:
");scanf("%d",&n);
}
shoudong_maze(m,n);
print_maze(m,n);
mgpath(maze,m,n);
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>39)||(n<=0||n>39))
{printf("\n抱歉,你输入的行列数超出预设围(0-39,0-39),请重新输入:
\n\n");
printf("请输入行数:
");scanf("%d",&m);
printf("\n");
printf("请输入列数:
");scanf("%d",&n);
}
zidong_maze(m,n);
print_maze(m,n);
mgpath(maze,m,n);
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;
}
}
}
总结
通过这段时间的课程设计,本人对计算机的应用,数据构造的作用以及C语言的使用都有了更深的了解。
尤其是C语言的进步让我深刻的感受到任何所学的知识都需要实践,没有实践就无法真正理解这些知识以及掌握它们,使其成为自己的财富。
在理论学习和上机实践的各个环节中,通过自主学习和请教教师,我收获了不少。
当然也遇到不少的问题,也正是因为这些问题引发的思考给我带了收获。
从当初不喜欢上机写程序到现在能主动写程序,从当初拿着程序不只如何下手到现在知道如何分析问题,如何用专业知识解决实际问题的转变,我发现无论是专业知识还是动手能力,自己都有很大程度的提高。
在这段时间里,我对for、while等的循环函数用法更加熟悉,逐渐形成了较好的编程习惯。
在教师的指导帮助下,同学们课余时间的讨论中,这些问题都一一得到了解决。
在程序的调试能力上,无形中得到了许多的提高。
例如:
头文件的使用,变量和数组的围问题,定义变量时出现的问题等等。
在实际的上机操作过程中,不仅是让我们了解数据构造的理论知识,更重要的是培养解决实际问题的能力,所以相信通过此次实习可以提高我们分析设计能力和编程能力,为后续课程的学习及实践打下良好的根底。
在这次短短的课程实践里,我们得到了卢鹏丽教师的关心和帮助。
她给了我们很多的信息,与我们一起探讨问题,询问我们遇到了哪些问题并耐心给予指导。
当我们遇到技术上难以解决的问题时,她就会指导我们解决问题,她把自己多年来积累的经历教授给我们,使我们顺利地完成了课程实践任务。
时间过得真快,大学生活不知不觉就走过了一年,一年的大学学习和课程实践阶段的提高,使我们本身知识得到提高的同时,也增强了我们对未来工作的信心,我们相信自己未来的学习更使我们有能力胜任将来的工作。
参考文献
1严蔚敏,吴伟民.?
数据构造〔C语言版〕?
.清华大学.
2严蔚敏,吴伟民.?
数据构造题集〔C语言版〕?
.清华大学.
3?
DATASTRUCTUREWITHC++?
.WilliamFord,WilliamTopp.清华大学〔影印版〕.
4谭浩强.?
c语言程序设计?
.清华大学.
5.数据构造与算法分析〔Java版〕,APracticalIntroductiontoDataStructuresandAlgorithmAnalysisJavaEditionCliffordA.Shaffer,铭,晓丹译 电子工业2001年1月
致
在这样的一个程序设计中,靠一个人的单打独斗是不可能完成的。
在这次设计过程中,在开场的构思、设想,源代码编写时的提示,上机时精心的指点,有了教师和舍友以及身边同学的指导、意见和帮助,最终才完成了这个迷宫求解问题系统的设计与实现。
所以在这里要对以上教师及同学表示感,非常感他们的帮助。
而且在这次课程设计中我学习到了很多很多。
附件Ⅰ局部源程序代码
voidmain()
{inti,m,n,cycle=0;
while(cycle!
=(-1))
{
printf("*************************************************************\n");printf("欢送进入迷宫求解系统\n");
printf("设计者:
兰理工计算机4班永刚\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>39)||(n<=0||n>39))
{printf("\n抱歉,你输入的行列数超出预设围(0-39,0-39),请重新输入:
\n\n");
printf("请输入行数:
");scanf("%d",&m);
printf("\n");
printf("请输入列数:
");scanf("%d",&n);
}
shoudong_maze(m,n);
print_maze(m,n);
mgpath(maze,m,n);
if(X!
=0)result_maze(m,n);
printf("\n\nPressEnterContiue!
\n");getchar();while(getchar()!
='\n');break;
case2:
printf("\n请输入行数