迷宫的生成与路由.docx
- 文档编号:4741225
- 上传时间:2022-12-08
- 格式:DOCX
- 页数:31
- 大小:277.72KB
迷宫的生成与路由.docx
《迷宫的生成与路由.docx》由会员分享,可在线阅读,更多相关《迷宫的生成与路由.docx(31页珍藏版)》请在冰豆网上搜索。
迷宫的生成与路由
数据结构课程设计报告撰写要求
(一)纸张与页面要求
1.采用国际标准A4型打印纸或复印纸,纵向打印。
2.封页和页面按照下面模板书写(正文为:
小四宋体1.5倍行距)。
3.图表及图表标题按照模板中的表示书写。
(二)课设报告书的内容应包括以下各个部分:
(按照以下顺序装订)
1.封页(见课设模版)
2.任务书(学生教师均要签字,信息填写完整)
3.目录
4.正文一般应包括以下内容:
(1)题目介绍和功能要求(或描述)
课程设计任务的详细描述(注意不能直接抄任务书),将内容做更详细的具体的分析与描述;
(2)系统功能模块结构图
绘制系统功能结构框图及主要模块的功能说明;
(3)使用的数据结构的描述:
数据结构设计及用法说明;
(4)涉及到的函数的描述;
(5)主要算法描述(程序流程图)
(6)给出程序测试/运行的结果
设计多组数据加以描述(包括输入数据和输出结果)
(7)课程设计的总结及体会
(8)参考文献
格式要求:
[1]作者,等.书名.出版地:
出版社,出版年
5.附录:
程序清单(应带有必要的注释)
沈阳航空航天大学
课程设计报告
课程设计名称:
数据结构课程设计
课程设计题目:
迷宫的生成与路由
院(系):
计算机学院
专业:
计算机科学与技术
班级:
学号:
姓名:
指导教师:
1题目介绍和功能要求
1.1题目介绍
设计算法生成一个N*M(N行M列)的迷宫,并完成迷宫的组织和存储。
实现两种不同的迷宫路由算法:
广度搜索,深度优先搜索。
要求:
1.N和M是用户可配置的,缺省值为50和50。
2.迷宫的入口和出口分别在第0行和第N-1行上,随机选择。
3.生成的迷宫要求是连通的。
4.实现图像化界面(选作)。
1.2功能要求
(1)迷宫用二维数组表示;
(2)rand()函数随机确定入口和出口,使用真随机数使得每次随机的结果不同。
(3)入口和出口间的路径是连通的,使用数据结构的并查集来表示连通性。
(4)使用数据结构的两种搜索方式:
深度和广度优先搜索来确定入口和出口间的路径。
2系统功能模块结构图
2.1系统功能结构框图
图2.1系统功能结构框图
2.2系统主要模块的功能说明
1.初始化迷宫模块:
Inint()函数用来初始化迷宫,使用二维数组来表示迷宫,假设迷宫是用一个个封闭的小格子组成的,每个格子的四周是封闭的。
首先随机生成入口和出口的位置。
2.随机化生成迷宫路径模块:
并查集(数据结构):
(1)并查集可以用来表示元素之间的集合关系,即这些元素是不是属于哪个集合。
通俗理解是,若两个元素是属于统一集合,就将这两个元素并在一起。
(2)存储结构上,用树结构模拟。
一开始,每个元素自己构成一个集合,所以自己构成一棵树。
然后,若有两个元素并成一个集合,则将这两个元素所在的树,合并成一棵树。
具体实现的话,就是将一棵树的根看成是另一棵树根的新根。
(3)并查集的作用是可以统计并判定两个元素是否属于统一集合。
利用并查集实现入口和出口的连通:
find()函数和unite()函数,初始化迷宫的每个元素都是一个独立的集合,随机化选择一个数组元素,再随机选择一个方向,使其与相邻的元素放入同一集合。
直到入口和出口处于同一个集合。
3.深度优先搜索模块:
Bfs()函数利用队列从入口开始找到一条路径抵达出口。
4.深度优先搜索模块:
Dfs()函数利用递归从入口开始找到一条路径抵达出口。
5.形象化显示迷宫模块:
迷宫数组中任意相邻的元素如果属于同一集合,则之间是连通的,否则不连通,并标注出入口和出口的位置。
3使用的数据结构的描述
3.1数据结构设计
并查集:
并查集可以用来表示元素之间的集合关系,即这些元素是不是属于哪个集合。
通俗理解是,若两个元素是属于统一集合,就将这两个元素并在一起。
存储结构上,用树结构模拟。
一开始,每个元素自己构成一个集合,所以自己构成一棵树。
然后,若有两个元素并成一个集合,则将这两个元素所在的树,合并成一棵树。
具体实现的话,就是将一棵树的根看成是另一棵树根的新根。
并查集的作用是可以统计并判定两个元素是否属于统一集合。
广度优先搜索:
(1)从队列头取出一个结点,检查它按照扩展规则是否能够扩展,如果能则产生一个新节点。
(2)检查新生成的结点,看它是否已在队列中存在,如果新节点已在队列中,就放弃此节点,然后回到第
(1)步。
否则,加入队尾。
(3)检查新节点是否为目标结点,如果是则搜索成功,程序结束,如果不是,回到第
(1)步,再从队列头取出结点进行扩展
(4)当需要给出解的路径时,则要保存每个节点的来源,也就是它是从哪个结点扩展来的。
深度优先搜索:
初始化所有顶点均未被访问过,选择初始点后,递归调用以下步骤:
(1)访问搜索到的未被访问的邻接点;
(2)将此顶点的visited数组元素值置1;
(3)搜索该顶点的违背访问的邻接点,若该邻接点存在,则从此邻接点开始进行同样的访问和搜索。
3.2数据结构用法说明
并查集:
首先将所有的迷宫元素处理成独立的集合,father[i]=i;当选择将两个元素连通时,即将两个元素处于同一集合下,具体做法是将一棵树的根看成是另一棵树根的新根。
假设元素i的树根是b,元素j的树根是h,则将father[b]=h;即将两个元素放在了同一集合里,也就是两个元素的树根相同。
广度优先搜索:
搜索时用到了队列,广度优先搜索的结果是最优的,也就是从入口到出口的最短的路径,因为要知道具体的路径,所以需要标记每个入队列的元素的来源,这样就能从出口返回到入口。
深度优先搜索:
搜索时用到了栈,递归操作是深度搜索的关键,标记的添加与删除是非常重要的。
我们需要存储遍历的路径,每当我们深入一层递归时,我们需要将坐标入栈,每当递归回退时,表示这个位置不合适,我们将出栈,最后,当我们搜索到出口时,将栈输出即为遍历路径。
4函数的描述
4.1主要函数设计
1.inint()函数:
作用:
按照规定尺寸申请二维数组表示迷宫,并将每个数组元素设置为独立的集合,用并查集表示,规定每个元素与四周相邻的元素是不连通的,用arry[].state[]表示,当为1表示连通,0时表示不连通。
2.voidmaze()函数:
作用:
随机生成迷宫。
构造路径从入口到出口是连通的。
按并查集来说就是将入口和出口以及二者间的路径元素都处于同一个集合,也就是有着相同的树根。
3.voidbfs()函数:
作用:
广度优先搜索从入口遍历至出口,并记录具体路径。
4.voiddfs()函数:
作用:
深度优先搜索从入口遍历至出口,并记录具体路径。
5.voidfinalprint()函数:
作用:
按照遍历路径扫描二维数组,形象化表示迷宫。
4.2主要函数流程图
Inint():
图4.2.1初始化迷宫函数流程图
Voidmaze():
否是
图4.2.2随机生成连通函数流程图
Voidbfs()函数:
是
否
图4.2.3广度优先遍历迷宫函数流程图
Voiddfs()函数:
是
否
是
否
图4.2.4深度优先遍历迷宫函数流程图
5程序测试和运行的结果
5.1程序测试
由用户自行规定迷宫的尺寸
截图5.1.1:
迷宫的初始化
迷宫的随机形成
截图5.1.2:
迷宫的形成
5.2运行结果
迷宫的广度优先搜索
截图5.2.1:
迷宫的广度搜索
迷宫的深度优先搜索
图5.2.2:
迷宫的深度优先搜索
输出迷宫
图5.2.3:
输出迷宫
参考文献
[1]高富平,张楚.电子商务法[M].北京:
北京大学出版社,2002
[2]谭浩强著.C程序设计(第三版).北京:
清华大学出版社,2005
[3]数据结构:
C语言版/严蔚敏,吴伟明编著.—北京:
清华大学出版社,2007
附录(关键部分程序清单)
#include
#include
#include
#include
structnode
{
intstate[4];//0123表示上下左右四扇门的闭合情况,0表示关闭,1表示打开
}arry[5000];
structstu
{
intx,y;
intloc;
}q[10000],stack[1000],cun[100000],bor[1000];
intn,m,en,ex,father[5000],front,rear,vis[10000][10000],der[4][2]={0,1,0,-1,-1,0,1,0},mark[1000][1000],top,xian[1000][1000];//将二维数组转化为一维数组,二维坐标(a,b),转化为一维坐标a*m+b;一维坐标x,转化为二维坐标(x/m,x%m),二维数组的行和列从0开始
intfind(intx)
{
if(father[x]==x)
returnx;
else
father[x]=find(father[x]);
}
voidunite(inthx,inthy)
{
inti,j;
i=find(hx);
j=find(hy);
father[i]=j;
}
voidinint()
{
for(inti=0;i { for(intj=0;j { father[i*m+j]=i*m+j; printf("%d",father[i*m+j]); } printf("\n"); } for(intk=0;k arry[k].state[0]=arry[k].state[1]=arry[k].state[2]=arry[k].state[3]=0;//所有的门都是闭合的 } voidnprint() { inti,j; printf(""); for(i=0;i { if(i<10) printf("%d",i); else printf("%d",i); } printf("\n"); printf(""); for(i=0;i { if(i==en) printf(""); else printf("_"); } printf("\n"); for(i=0;i { if(i<10) printf("%d",i); else printf("%d",i); printf("|"); for(j=0;j { if(arry[i*m+j].state[3]==1) printf(""); else printf("|"); } printf("\n"); printf(""); for(j=0;j { if(i==n-1&&j==ex) printf(""); else { if(arry[i*m+j].state[1]==1) printf(""); else printf("-"); } } printf("\n"); } } voidmaze()//随机生成迷宫 { introw,col,num,nrow,ncol; clock_tstart_time; start_time=clock();//计时函数,数据类型是clock_t(长整型,毫秒),在time.h文件中syx while(find(en)! =find((n-1)*m+ex))//入口和出口不连通 { row=rand()%n;//随机找出一个房间 col=rand()%m; num=rand()%4; switch(num) { case0: //与上相通 { nrow=row-1; if(row==0) continue; else { if(find(nrow*m+col)! =find(row*m+col))//判断是否连通,如果连通,说明曾经操作过,否则,相连通 { arry[row*m+col].state[0]=arry[nrow*m+col].state[1]=1;//将两个相邻方格的相对应的墙拆掉 unite(nrow*m+col,row*m+col); } } break; } case1: //与下相通 { nrow=row+1; if(row==n-1) continue; else { if(find(nrow*m+col)! =find(row*m+col)) { arry[row*m+col].state[1]=arry[nrow*m+col].state[0]=1; unite(nrow*m+col,row*m+col); } } break; } case2: //与左相通 { ncol=col-1; if(col==0) continue; else { if(find(row*m+col)! =find(row*m+ncol)) { arry[row*m+col].state[2]=arry[row*m+ncol].state[3]=1; unite(row*m+col,row*m+ncol); } } break; } case3: //与右相通 { ncol=col+1; if(col==m-1) continue; else { if(find(row*m+col)! =find(row*m+ncol)) { arry[row*m+col].state[3]=arry[row*m+ncol].state[2]=1; unite(row*m+col,row*m+ncol); } } break; } } } } voidbfs()//xy为入口的坐标 { inti,j,k,px,py,hx,hy; while(front { px=q[front].x; py=q[front].y; if(px==n-1&&py==ex) return; for(i=0;i<4;i++) { hx=px+der[i][0]; hy=py+der[i][1]; if(vis[hx][hy]==0&&hx>=0&&hx { if(px==hx&&hy==py-1)//左移 if(arry[px*m+py].state[2]==1) { q[rear].x=hx; q[rear].y=hy; vis[hx][hy]=1; q[rear].loc=px*m+py; rear++; } if(px==hx&&hy==py+1)//右移 if(arry[px*m+py].state[3]==1) { q[rear].x=hx; q[rear].y=hy; vis[hx][hy]=1; q[rear].loc=px*m+py; rear++; } if(hy==py&&hx==px-1)//上移 if(arry[px*m+py].state[0]==1) { q[rear].x=hx; q[rear].y=hy; vis[hx][hy]=1; q[rear].loc=px*m+py; rear++; } if(hy==py&&hx==px+1)//下移 if(arry[px*m+py].state[1]==1) { q[rear].x=hx; q[rear].y=hy; vis[hx][hy]=1; q[rear].loc=px*m+py; rear++; } } } front++; } } voidinitmaze() { inti,j,k; printf(""); for(i=0;i { if(i<10) printf("%d",i); else printf("%d",i); } printf("\n"); printf(""); for(i=0;i { printf("_"); } printf("\n"); for(i=0;i { if(i<10) printf("%d",i); else printf("%d",i); printf("|"); for(j=0;j { printf("|"); } printf("\n"); printf(""); for(j=0;j { printf("-"); } printf("\n"); } } voidprintbfs() { intj,rx,ry,k; printf("打印广度优先搜索的存储顺序: \n"); for(j=0;j<=front;j++) printf("(%d%d)",q[j].x,q[j].y); printf("\n"); intcount=0; while(q[front].loc! =(q[front].x*m+q[front].y)) { stack[count].x=q[front].x; stack[count].y=q[front].y; count++; rx=q[front].loc/m; ry=q[front].loc%m; for(k=front-1;k>=0;k--) if(q[k].x==rx&&q[k].y==ry) front=k; } printf("根据广度搜索记录父级地址打印从入口到出口的路径如下: \n"); for(intt=count-1;t>=0;t--) printf("(%d%d)\n",stack[t].x,stack[t].y); } voiddfs(intpx,intpy) { inti,j,k,hx,hy; cun[top].x=px; cun[top].y=py; top++; if(px==n-1&&py==ex) { for(i=0;i { bor[i].x=cun[i].x; bor[i].y=cun[i].y; } bor[i].x=-1; return; } for(i=0;i<4;i++) { hx=px+der[i][0]; hy=py+der[i][1]; if(hx>=0&&hx { if(px==hx&&hy==py-1)//左移 if(arry[px*m+py].state[2]==1) { mark[hx][hy]=1; dfs(hx,hy); mark[hx][hy]=0; top--; } if(px==hx&&hy==py+1)//右移 if(arry[px*m+py].state[3]==1) { mark[hx][hy]=1; dfs(hx,hy); mark[hx][hy]=0; top--; } if(hy==py&&hx==px-1)//上移 if(arry[px*m+py].state[0]==1) { mark[hx][hy]=1; dfs(hx,hy); mark[hx][hy]=0; top--; } if(hy==py&&hx==px+1)//下移 if(arry[px*m+py].state[1]==1) { mark[hx][hy]=1; dfs(hx,hy); mark[hx][hy]=0; top--; } } } mark[px][py]=0; } voidfinalprint() { inti,j; printf(""); for(i=0;i { if(i<10) printf("%d",i); else printf("%d",i); } printf("\n"); printf(""); for(i=0;i { if(i==en) printf(""); else printf("_"); } printf("\n"); for(i=0;i { if(i<10) printf("%d",i); else printf("%d",i); printf("|"); for(j=0;j { if(arry[i*m+j].state[3]==1)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 迷宫 生成 路由