数据结构课程设计迷宫求解
- 格式:doc
- 大小:314.50 KB
- 文档页数:21
数据结构课程设计迷宫问题求解正文:一、引言在数据结构课程设计中,迷宫问题求解是一个经典且常见的问题。
迷宫问题求解是指通过编程实现在迷宫中找到一条从起点到终点的路径。
本文将详细介绍如何用数据结构来解决迷宫问题。
二、问题分析1.迷宫定义:迷宫是由多个格子组成的矩形区域,其中包括起点和终点。
迷宫中的格子可以是墙壁(无法通过)或者通道(可以通过)。
2.求解目标:在给定的迷宫中,找到从起点到终点的一条路径。
3.输入:迷宫的大小、起点坐标、终点坐标以及墙壁的位置。
4.输出:从起点到终点的路径,或者提示无解。
三、算法设计1.基础概念a) 迷宫的表示:可以使用二维数组来表示迷宫,数组的元素可以是墙壁、通道或者路径上的点。
b) 坐标系统:可以使用(x, y)来表示迷宫中各个点的坐标。
c) 方向定义:可以用上、下、左、右等四个方向来表示移动的方向。
2.深度优先搜索算法(DFS)a) 算法思想:从起点开始,沿着一个方向一直走到无法继续为止,然后回退到上一个点,再选择其他方向继续探索。
b) 算法步骤:i) 标记当前点为已访问。
ii) 判断当前点是否为终点,如果是则返回路径;否则继续。
iii) 遍历四个方向:1.如果该方向的下一个点是通道且未访问,则继续向该方向前进。
2.如果该方向的下一个点是墙壁或已访问,则尝试下一个方向。
iv) 如果四个方向都无法前进,则回退到上一个点,继续向其他方向探索。
3.广度优先搜索算法(BFS)a) 算法思想:从起点开始,逐层向外探索,直到找到终点或者所有点都被访问。
b) 算法步骤:i) 标记起点为已访问,加入队列。
ii) 循环以下步骤直到队列为空:1.取出队首元素。
2.判断当前点是否为终点,如果是则返回路径;否则继续。
3.遍历四个方向:a.如果该方向的下一个点是通道且未访问,则标记为已访问,加入队列。
iii) 如果队列为空仍未找到终点,则提示无解。
四、算法实现1.选择合适的编程语言和开发环境。
数据构造课程设计陈述------迷宫问题求解学号:1315925375姓名:刘晓龙班级:13移动1班指点先生:钱鸽目次一.需求剖析1二.数据构造21. 数据构造设计斟酌22. 逻辑构造存储构造3三.算法设计3四.调试剖析8五.程序实现及测试8六.领会及缺少之处9七.参考文献9八.源代码10一.需求剖析本课程设计是解决迷宫求解的问题,从进口动身,顺某一偏向向前摸索,若能走通,则持续往前走;不然沿原路退回,换一个偏向再持续摸索,直至所有可能的通路都摸索到为止.为了包管在任何地位上都能沿原路退回,显然须要用一个落后先出的构造来保管从进口到当前地位的路径.是以,在求迷宫通路的算法中要运用“栈”的思惟假设“当前地位”指的是“在搜刮进程中的某一时刻地点图中某个方块地位”,则求迷宫中一条路径的算法的根本思惟是:若当前地位“可通”,则纳入“当前路径”,并持续朝“下一地位”摸索,即切换“下一地位”为“当前地位”,如斯反复直至到达出口;若当前地位“不成通”,则应顺着“来向”退回到“前一通道块”,然后朝着除“来向”之外的其他偏向持续摸索;若该通道块的周围4个方块均“不成通”,则应从“当前路径”上删除该通道块.所谓“下一地位”指的是当前地位周围4个偏向(上.下.左.右)上相邻的方块.假设以栈记载“当前路径”,则栈顶中存放的是“当前路径上最后一个通道块”.由此,“纳入路径”的操纵即为“当前地位入栈”;“从当前路径上删除前一通道块”的操纵即为“出栈”.二.数据构造1. 数据构造设计斟酌1) 树立一个二维数组暗示迷宫的路径(0暗示通道,1暗示墙壁);2) 创建一个栈,用来存储“当前路径”,即“在搜刮进程中某一时刻地点图中某个方块地位”.2. 逻辑构造存储构造1) 创建一个Int类型的二维数组int maze[n1][n2],用来存放0和1 (0暗示通道,1暗示墙壁);2) 创建一个构造体用来储存数组信息构造体:typedef struct//迷宫内部设置{int shu[16][16];int row;int col;}Maze;创造一个链栈struct node{int row;int col;struct node *next;};三.算法设计起首,创建数组的大小,此数组大小请求用户本身输入.具体算printf("输出神宫的外形!\n");scanf("%d%d",&x,&y);Maze m;CreatInit(&m,x,y);函数:void CreatInit(Maze *m,int x,int y)//创建迷宫{printf("please input number:\n");int i,j;for(i=0;i<=x;i++){for(j=0;j<=y;j++)m->shu[i][j] = 2;}for(i=1;i<=x;i++)for(j=1;j<=y;j++)scanf("%d",&m->shu[i][j]);m->row = x;m->col = y;}个中的0和1分离是暗示通路和障碍,界说的数组其实就是迷宫的其次,产生迷宫,算法:for(i=1;i<=x;i++){for(j=1;j<=y;j++)printf("%d\t",m.shu[i][j]);printf("\n");}最后,迷宫寻路,在寻路的时刻,我们应从输入的进口地位进出神宫,当迷宫的进口处有障碍或者出口被堵,再或者没有通路时全部程序停止,并输出迷宫无解的提醒.假如迷宫求解进程中没有消失无解情形,那么在求解的进程中,会输出迷宫的通路路径,并且输出坐标值,让运用者更清晰路径的走法.在寻路的进程中,每走过一个格,谁人格得知就会被赋值为-1,用来标识表记标帜此处已走过,免除了来往返回的重走,以免消失逝世轮回,如许程序就能从进口进入到迷宫当中.假如在迷宫当中没有通路的话,可以停止轮回输出“迷宫无解!”,则当迷宫假如消失有解时,就会输出路径.如许就简略的实现了,有解无解的输出.从而实现了请求的程序!代码如下:while((x1 >= 1 && x1 <= x) || (y1 >= 1 && y1 <= y)){if(x1 == x2 && y1 == y2){break;}if(m.shu[x1][y1+1] == 0 ) {y1=y1+1;push(x1,y1);m.shu[x1][y1] = -1; continue;}if(m.shu[x1-1][y1]==0 ) {x1=x1-1;push(x1,y1);m.shu[x1][y1] = -1; continue;}if(m.shu[x1][y1-1]==0 ) {y1=y1-1;push(x1,y1);m.shu[x1][y1]= -1;continue;}if(m.shu[x1+1][y1]==0 ){x1=x1+1;push(x1,y1);m.shu[x1][y1]= -1;continue;}pop();if(p->next==NULL)break;x1=p->row;y1=p->col;}if(x1 == x2 && y1 == y2){while(p->next != NULL){printf("%d %d\n",p->row,p->col); pop();}}elseprintf("No Answer !!!");个中要追求所有的通路,在这里则运用了一个while轮回,如许可以找到所有的通路.图解剖析:整体流程图:迷宫内部操纵流程图:四.调试剖析第一个问题,在刚开端的调试进程中,我们碰到了,无法断定走过的旅程,从而消失了逝世轮回,导致程序不克不及正常进行,但是经由我们的评论辩论,我们想出用标识表记标帜的办法来解决,也就是让走过的旅程全给标示了,如许就不会再走反复的路.第二个问题,就是性用菜单来实现操纵,那样程序的操纵性就会更强,所以我们就要把所有的办法,给写成一个个的函数来挪用,如许就碰到了参量传递的问题,但是经由我们的参考以及从书本上的实例,我们慢慢地更深的懂得到了参量传递的运用,那么这个问题也就水到渠成了.从此我们实现了菜单操纵!五.程序实现及测试运行界面:开端界面六.领会及缺少之处经由过程此次课程设计,是我对于数据构造有了更深的懂得,更新的熟悉.数据构造是一门主要的课程,只稀有据构造学得扎实了,才干对于盘算机有更深的运用,所以学好数据构造是很主要的.经由两周的上机设计,我实现了简略的迷宫求解,可以或许简略的实现求解进程.但是还消失着缺少之处,本程序不克不及轮回履行,只能履行一次.有待改良!七.参考文献1.《数据构造(c说话版) 》严蔚敏清华大学出版社2.《数据构造试验教程》李业丽.郑良斌《数据构造》高教出版社3.《数据构造习题》李春保清华大学出版社4.《数据构造习题》严蔚敏清华大学出版社5.《C说话与数据构造》王立柱清华大学出版社6.《数据构造(C说话篇)习题与解析》李春保清华大学出版社.八.源代码#include <stdio.h>#include <stdlib.h>typedef struct//迷宫内部设置{int shu[16][16];int row;int col;}Maze;struct node{int row;int col;struct node *next;};struct node *p;void push(int x1,int y1){struct node *a;a=(struct node *)malloc(sizeof(struct node)); a->row=x1;a->col=y1;a->next=p;p=a;}void pop(void){struct node *q;q=p;p=p->next;free(q);}void CreatInit(Maze *m,int x,int y)//创建迷宫{printf("please input number:\n");int i,j;for(i=0;i<=x;i++){for(j=0;j<=y;j++)m->shu[i][j] = 2;}for(i=1;i<=x;i++)for(j=1;j<=y;j++)scanf("%d",&m->shu[i][j]);m->row = x;m->col = y;}void menu(){printf("\n*************************\n"); printf("迎接进出神宫\n");printf("1.进出神宫\n");printf("2.退出\n");}int main(void){int t;int x,y;int x1,y1;int x2,y2;int i,j;while(1){menu();printf("请选择:");scanf("%d",&t);if(t == 2)break;printf("输出神宫的外形!\n");scanf("%d%d",&x,&y);Maze m;CreatInit(&m,x,y);for(i=1;i<=x;i++){for(j=1;j<=y;j++)printf("%d\t",m.shu[i][j]);printf("\n");}printf("输入进口地位:");scanf("%d%d",&x1,&y1);printf("输入出口的地位:");scanf("%d%d",&x2,&y2);p=(struct node *)malloc(sizeof(struct node)); p->row=0;p->col=0;p->next=NULL;push(x1,y1);while((x1 >= 1 && x1 <= x) || (y1 >= 1 && y1 <= y)) {if(x1 == x2 && y1 == y2){break;}if(m.shu[x1][y1+1] == 0 ){y1=y1+1;push(x1,y1);m.shu[x1][y1] = -1;continue;}if(m.shu[x1-1][y1]==0 ){x1=x1-1;push(x1,y1);m.shu[x1][y1] = -1;continue;}if(m.shu[x1][y1-1]==0 ){y1=y1-1;push(x1,y1);m.shu[x1][y1]= -1; continue;}if(m.shu[x1+1][y1]==0 ) {x1=x1+1;push(x1,y1);m.shu[x1][y1]= -1; continue;}pop();if(p->next==NULL) break;x1=p->row;y1=p->col;}if(x1 == x2 && y1 == y2) {while(p->next != NULL) {printf("%d %d\n",p->row,p->col); pop();}}elseprintf("No Answer !!!");}return 0;}。
沈阳航空航天大学课程设计报告课程设计名称:数据结构课程设计课程设计题目:迷宫算法院(系):计算机学院专业:计算机科学与技术班级:学号:姓名:指导教师:目录1 课程设计介绍 (1)1.1课程设计内容 (1)1.2课程设计要求 (1)2 课程设计原理 (2)2.1课设题目粗略分析 (2)2.2原理图介绍 (3)2.2.1 功能模块图 (3)2.2.2 流程图分析 (4)3 数据结构分析 (8)3.1存储结构 (8)3.2算法描述 (8)4 调试与分析 (11)4.1调试过程 (11)4.2程序执行过程 (11)参考文献 (15)附录(关键部分程序清单) (16)1 课程设计介绍1.1 课程设计内容编写算法能够生成迷宫,并且求解迷宫路径(求解出任意一条到出口的路径即可):1.迷宫用上下左右四种走法;2.迷宫的大小和复杂程度可以由用户定义;3.入口出口也由用户自己选择。
1.2 课程设计要求1.不必演示求解过程,只需要输出迷宫求解的路径;2.参考相应资料完成课设。
2 课程设计原理2.1 课设题目粗略分析根据课设题目要求,拟将整体程序分为四大模块。
以下是四个模块的大体分析:1 建立迷宫:要建立迷宫首先就要建立存储结构,这里我用栈的方式建立的。
根据用户输入的迷宫的大小(我设置的最大值为25可以根据要求调解);2 设置迷宫:这里将0设置围墙,1是可以通过的路径,-1是不可以通过路径,外墙是以设计好的,内墙需要用户来设置,障碍的难度可由用户自行定义;3 寻找路径:寻找路径我设置了四个方向{0,1},{1,0},{0,-1},{-1,0}移动方向,依次为东南西北,首先向东走,若不成功则转换方向,成功则继续前进,将走过的路径进行标记,然后存入栈中;4 输出结果:输出的结果分为两种,一种是用户建立的迷宫主要是让用户检查是否符合要求,第二种输出的是寻找完后的路径,路径用1 2 3 4···来表示。
课程设计报告课题名称:迷宫问题姓名:xxx学号:200816020239专业:电气与信息工程学院班级:通信08102指导教师:目录第一部分程告⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯ 3第一章程目的⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯ 3第二章程内容和要求⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯ 4描述⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯ 4要求⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯ 4第三章程体方案及解析⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯ 4解析⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯ 4大纲⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯7⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯7解析⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯10果⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯10参照文件⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯12 第二部分程⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯13附 (源代 )⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯14第二部分课程设计报告第一章课程设计目的到列是一种特其他性表是不的,本次的目的在于使学生深入认识列的特色,以便在背景下灵便运用它,同将牢固种数据构的构造方法第二章课程设计内容和要求2.1 问题描述:迷是取自心理学的一个古典。
在中,把一只老鼠从一个无大盒子的放入,在盒子中置了多,行方向形成了多阻。
盒子有一个出口,在出口放置一奶酪,吸引老鼠在迷中找道路以到达出口。
同一只老鼠重复行上述,向到达老鼠从入口走到出口,而不走一步。
老鼠多次最学会走通迷的路。
一个算机程序任意定的矩形迷以下 A 所示,求出一条从入口到出口的通路,或得出没有通路的。
A2.2 设计要求:要求设计程序输出以下:(1)成立一个大小为 m×n的任意迷宫(迷宫数据可由用户输入或由程序自动生成),并在屏幕上显示出来;(2 )找出一条通路的二元组(i,j )数据序列,( i,j )表示通路上某一点的坐标。
(3 )用一种标志(如数字8 )在迷宫中标出该条通路;(4 )在屏幕上输出迷宫和通路;(5 )上述功能可用菜单项选择择。
迷宫求解数据结构课程设计《数据结构》课程设计题目:迷宫求解班级:学号:作者姓名:指导教师:2012年12月11日目录1.需求分析 (1)2.概要设计 (1)2.1.数据结构 (1)2.1.1.逻辑结构 (1)2.1.1.存储结构 (2)2.2.基本操作 (3)2.2.1.迷宫中栈的基本操作 (3)2.2.2.迷宫的抽象数据类型 (3)2.2.3.本程序包含三个模块 (4)3.详细设计 (5)4.调试与分析 (9)5.用户手册 (9)6. 测试结果 (10)7. 附录 (12)8. 参考文献 (12)9、心得体会 (12)10、小组成员工作分配 (13)一、需求分析(1)以二维数组maze[n+2][m+2]表示迷宫,其中:maze[0][j]和maze[n+1][j](0<=j<=m+1)及maze[i][0]和maze[i][m+1](0<=i<=j+1)为添加的一圈障碍。
数组中以元素值为0的表示通路,1表示障碍,限定迷宫的大小,m,n<=0。
(2)迷宫的入口位置和出口位置可由用户自行设定。
(3)如设定的迷宫处在通路,则值输出迷宫中的通路,即0,现实的0连起来就是一个迷宫通路路径;如设定的迷宫中不出在通路,则输出“该迷宫找不到通路!”;(4)测试样例:输入迷宫的长宽为5和6,输入迷宫为:1 0 0 1 1 10 0 1 1 1 11 0 0 0 1 10 1 0 1 1 11 1 0 0 0 0当入口位置为(1,2),出口位置为(5,6)时,则输出数据为:# # # # # # # ## 0 ## 0 ## 0 0 ## 0 ## 0 0 0 0 ## # # # # # # #(5)程序执行的命令为:1、输入迷宫的尺寸;2、创建迷宫;3、输入迷宫的的出入口位置;4、求解迷宫;输出迷宫的解。
二、概要设计2.1.数据结构2.1.1、逻辑结构1)栈的定义:限定仅在表尾进行插入或删除操作的线性表;2)操作特性:后进先出;3) ADT定义:ADT Stack{数据对象:D={ai|ai∈CharSet,i=1,2,…,n,n>=0}数据关系:R1={<ai-1,ai>|ai-1,ai∈D,i=2,…,n}基本操作:InitStack(&S)操作结果:构造一个空栈S。
课程设计报告课程名称:数据结构报告题目:迷宫求解学生姓名:XX所在学院:信息科学与工程专业班级:软件工程学生学号:XXXXXXXXXXX指导教师:XXX课程设计任务书摘要本程序主若是求迷宫中从人口到出口的所有途径是一个经典的程序设计问题。
运算机解迷宫时,通经常使用的是“穷举求解”的方式,即从入口动身,顺某一方向向前探讨,假设能走通,那么继续往前走;不然沿原路返回,换一个方向在继续探讨,直至所有可能的通路都探讨完为止。
当前位置“可通”,那么纳入“当前途径”,并继续朝“下一名置”探讨,即切换为“下一名置”为“当前位置”,如此重复直至抵达出口;假设当前位置“不可通”,那么应顺着“来的方向”退回到“前一通道块”,假设该通道块的周围4个方块均“不可通”那么应从当前途径删除该通道块。
所谓“下一名置”指的是“当前位置”周围4个方向(东、南、西、北)上相邻的方块。
以栈S来记录“当前途径”,那么栈顶中寄存的是“当前途径上最后一个通道块”。
因此即为“当前途径入栈”;“从当前途径上删除前一通道块”为“出栈”。
在那个进程中能够输出迷宫所走通的途径,在这次课程设计中迷宫是由数组预先概念好的,不能由用户概念生成,能够加入随机函数,自动生成二维数组,还能够用户自己输入迷宫。
关键词:栈;存储结构;数组目录目录 (3)一、课题分析 (1)二、需求分析 (1)1. 主模块功能描述 (1)2. 子程序模块设计 (1)三、设计方案 (1)1.类设计 (1)int point_x; 序模块设计 (2)设计方案与实施与整体设计思想 (2)3. 主模块 (3)子模块 (4)主菜单 (5)功能A模块 (5)功能B模块 (5)功能C模块 (6)四、详细设计 (7)1.用结构体构建栈 (7)SElemType *top; 建类 (7)int point_x; 数组构建一个迷宫 (7)case 1: 戏移动操纵指令 (8)}戏移动操纵指令四个方向的实现 (8)else if ((map[point_x - 1][point_y] == 0 && direction != 5) || map[point_x - 1][point_y] == 3) 戏移动进程中假设是未找到通路,需要返回的指令 (9)}戏的主循环 (9)}戏的开始于终止 (10)if (map[point_x][point_y] == 3) 宫地图的查看与通关后的途径查询 (10)五、设计总结 (11)结论与心得 (11)五、参考文献 (12)一、课题分析(1)该题目为迷宫求解。
数据结构课程设计-迷宫问题正文:一、引言本文档旨在设计一个解决迷宫问题的数据结构课程项目。
迷宫问题是一个典型的寻路问题,要求从起点出发,在迷宫中找到一条路径到达终点。
迷宫由多个房间组成,这些房间之间通过门相连。
二、问题描述迷宫问题包含以下要素:1.迷宫的拓扑结构:迷宫由多个房间和门组成,每个房间有四面墙壁,每面墙壁可能有门或者是封闭的。
迷宫的起点和终点是预先确定的。
2.寻路算法:设计一个算法,在迷宫中找到一条从起点到终点的路径。
路径的选择标准可以是最短路径、最快路径或者其他约束条件。
3.可视化展示:实现一个可视化界面,在迷宫中展示起点、终点、路径,用于直观地演示解决方案。
三、设计思路1.数据结构设计:选择合适的数据结构来表示迷宫和路径,例如使用二维数组或者图来表示迷宫的拓扑结构,使用栈或队列来辅助寻路算法的实现。
2.寻路算法设计:可以使用深度优先搜索、广度优先搜索、Dijkstra算法、A算法等经典算法来实现寻路功能。
根据实际需求选择最合适的算法。
3.可视化展示设计:使用图形界面库(如Tkinter、Qt等)创建迷宫展示窗口,并实时更新迷宫的状态、路径的变化。
可以通过颜色、动画等方式增加交互性。
四、实现步骤1.创建迷宫:根据预设的迷宫大小,使用数据结构来创建对应的迷宫数据。
2.设定起点和终点:在迷宫中选择起点和终点的位置,将其标记出来。
3.寻路算法实现:根据选择的寻路算法,在迷宫中找到一条路径。
4.可视化展示:使用图形界面库创建窗口,并将迷宫、起点、终点、路径等信息展示出来。
5.更新迷宫状态:根据算法实现的过程,实时更新迷宫中的状态,并将路径显示在迷宫上。
附件:1.代码实现:包含迷宫创建、寻路算法实现和可视化展示的源代码文件。
2.演示视频:展示项目实际运行效果的视频文件。
法律名词及注释:1.数据结构:指在计算机科学中定义和组织数据的方式和方式的基础设施。
2.寻路算法:用于解决寻找路径的问题的算法。
迷宫游戏数据结构课程设计
1、简介
本文档旨在设计一个迷宫游戏的数据结构课程项目,通过使用合适的数据结构和算法,实现一个能够自动和解决迷宫的程序。
本项目将使用C++语言来实现。
2、功能需求
本项目的主要功能如下:
- 自动一个迷宫地图
- 实现玩家在迷宫地图中的移动
- 实现迷宫的解决算法
3、技术方案
本项目将采用以下技术方案来实现功能:
3.1 迷宫算法
为了一个随机的迷宫地图,我们将采用深度优先搜索(DFS)算法或者随机Prim算法来迷宫。
这些算法可以保证的迷宫是连通的且没有死胡同。
3.2 玩家移动
玩家将使用键盘输入来控制移动,通过获取键盘输入来实现玩
家在迷宫中的移动。
游戏将使用图形界面来呈现迷宫和玩家的位置。
3.3 迷宫解决算法
迷宫解决算法将使用广度优先搜索(BFS)算法或者深度优先搜
索(DFS)算法来搜索迷宫的路径。
该算法将从起点出发,逐步搜索
迷宫的每个可达点,直到找到终点或者遍历完整个迷宫。
4、开发计划
本项目的开发计划如下:
1、确定项目需求和技术方案 - 2天
2、实现迷宫算法 - 3天
3、实现玩家移动功能 - 2天
4、实现迷宫解决算法 - 3天
5、创建图形界面 - 2天
6、进行测试和调试 - 3天
7、完善文档和准备演示 - 2天
5、附件
本文档没有附件。
6、法律名词及注释
本文档没有涉及任何法律名词及注释。
考虑使用一个二维数组表示迷宫.所有的通路用0表示,墙用1表示,出口用9表示,入口用6表示,已经过点用3表示.输出走出迷宫的过程.从这个问题的求解过程中可以简单总结出两个算法,一是探路过程,二是输出路线.1.探路过程探路过程算法可归纳为:[1]从入口位置开始,检查东西南北四个方向上的通路,如果发现出口则成功退出,否则将所有通路坐标压入栈;[2]从栈中取出一个坐标,将其标记为当前位置(标记数字3),再次判断通路情况;[3]如此进行,直到发现出口则成功退出,若栈空而且未发现出口,则失败退出.这里使用到的回溯过程可描述为: 每到达一点时,会将所有可能的通路坐标(标记数字0的节点)压入栈.所以当到达一点,而不存在可能的通路时,自然没有相应的坐标压入栈,而此时便从栈中取出上一个点所压入的可能的一个通路坐标,并继续作通路判断,这便是一个回溯的过程.2.输出某一较短路线将所有在探路过程中经过的点(标记数字3的节点)按实际探路路线存入队列,对头为入口,队尾为出口.这些点可能存在绕路的情况,所以可用下面的算法输出某一较短路线.[1]将队尾(出口)节点设置为当前判断节点;[2]从当前判断节点(x,y)的前驱节点开始,向前遍历队列,如果发现相邻节点(其坐标可以为(x+1,y),(x-1,y),(x,y+1),(x,y-1)之一),则删除该相临节点至当前判断节点的前驱节点之间的所有节点;[3]将该相临节点设置为当前判断节点,继续判断相临节点;[4]当当前判断节点为对头节点时退出.该算法所得到的路线不一定是最短路线,想得到最短路线,可考虑使用树结构将所有由出口至入口的路线保留为一子树,树高最短的子树即为最短路线.但此算法可保证所得路线不会存在绕路情况.3.表示节点坐标的类public class MazeCell {private int x, y;//表示x轴y轴坐标public MazeCell() {}public MazeCell(int i, int j) {x = i;y = j;}public boolean equals(Object o) {if (!(o instanceof MazeCell))return false;MazeCell cell = (MazeCell) o;return cell.x == x && cell.y == y;}public String toString() {return x + "," + y;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}}4.所使用的栈数据结构import java.util.LinkedList;public class Stack<T> {private LinkedList<T> storage = new LinkedList<T>(); /** 入栈*/public void push(T v) {storage.addFirst(v);}/** 出栈,但不删除*/public T peek() {return storage.getFirst();}/** 出栈*/public T pop() {return storage.removeFirst();}/** 栈是否为空*/public boolean empty() {return storage.isEmpty();}/** 打印栈元素*/public String toString() {return storage.toString();}}5.求解迷宫问题import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.ListIterator;public class Maze {private int rows = 0, cols = 0;// 迷宫的行数与列数private char[][] store, path;// 迷宫矩阵private MazeCell currentCell, exitCell = new MazeCell(),entryCell = new MazeCell();// 当前节点,出口节点,入口节点private static final char EXIT = '9', ENTRY = '6', VISITED = '3';// 出口标记,入口标记,已经过节点标记private static final char PASS = '0', W ALL = '1';// 通路标记,墙标记private Stack<MazeCell> mazeStack = new Stack<MazeCell>();// 探路过程所使用栈private List<MazeCell> currentList = new LinkedList<MazeCell>();// 路经的路线队列public Maze() {// 构造迷宫int row = 0, col = 0;Stack<String> mazeRows = new Stack<String>();InputStreamReader isr = new InputStreamReader(System.in);BufferedReader buffer = new BufferedReader(isr);System.out.println("Enter a rectangular maze using the following" + " characters: \n6-entry\n9-exit\n1-wall\n0-passage\n"+ "Enter one line at a time; end with Ctrl-d;");try {String str = buffer.readLine();while (str != null) {row++;cols = str.length();str = "1" + str + "1";mazeRows.push(str);if (str.indexOf(EXIT) != -1) {exitCell.setX(row);exitCell.setY(str.indexOf(EXIT));}if (str.indexOf(ENTRY) != -1) {entryCell.setX(row);entryCell.setY(str.indexOf(ENTRY));}str = buffer.readLine();}} catch (IOException e) {e.printStackTrace();}rows = row;store = new char[rows + 2][];store[0] = new char[cols + 2];for (; !mazeRows.empty(); row--)store[row] = (mazeRows.pop()).toCharArray();store[rows + 1] = new char[cols + 2];for (col = 0; col <= cols + 1; col++) {store[0][col] = WALL;store[rows + 1][col] = WALL;}path = new char[rows + 2][];copyArray(store, path);}/** 二维数组复制*/private void copyArray(char[][] src, char[][] tar) {for (int i = 0; i < src.length; i++) {tar[i] = new char[cols + 2];for (int j = 0; j < src[i].length; j++)tar[i][j] = src[i][j];}}/** 二维数组输出*/private void display(PrintStream out, char[][] carray) {for (int row = 0; row <= rows + 1; row++)out.println(carray[row]);out.println();}/** 将未访问并可通路的节点压入栈*/private void pushUnvisited(int row, int col) {if (store[row][col] == PASS || store[row][col] == EXIT) mazeStack.push(new MazeCell(row, col));}/** 探路过程*/public void exitMaze(PrintStream out) {currentCell = entryCell;currentList.add(currentCell);out.println();while (!currentCell.equals(exitCell)) {int row = currentCell.getX();int col = currentCell.getY();display(System.out, store);if (!currentCell.equals(entryCell))store[row][col] = VISITED;pushUnvisited(row - 1, col);pushUnvisited(row + 1, col);pushUnvisited(row, col - 1);pushUnvisited(row, col + 1);if (mazeStack.empty()) {display(out, store);out.println("Failure");return;} else {currentCell = mazeStack.pop();currentList.add(currentCell);}}display(out, store);out.println("Success");}/** 得到某一输出路线*/private void getPath() {if (currentList.size() <= 0)return;MazeCell cell = currentList.get(currentList.size() - 1);while (cell != currentList.get(0)) {List<MazeCell> subList = currentList.subList(0, currentList.indexOf(cell));ListIterator<MazeCell> itr = subList.listIterator();while (itr.hasNext()) {MazeCell target = itr.next();if (adjoin(cell, target)) {removeElements(currentList.indexOf(target) + 1, currentList .indexOf(cell));cell = target;break;}}}}/** 删除队列中由from至to的连续元素*/private void removeElements(int from, int to) {int turn = to - from;while (turn > 0) {currentList.remove(from);turn--;}}/** 判断两个节点是否相邻*/private boolean adjoin(MazeCell current, MazeCell target) {if ((current.getX() == target.getX() + 1 || current.getX() == target.getX() - 1)&& (current.getY() == target.getY()))return true;if ((current.getY() == target.getY() + 1 || current.getY() == target.getY() - 1)&& (current.getX() == target.getX()))return true;return false;}/** 输出路线*/public void printPath(PrintStream out) {getPath();out.println("Path:");if (currentList.size() >= 2) {currentList.remove(currentList.size() - 1);currentList.remove(0);}Iterator<MazeCell> itr = currentList.iterator();while (itr.hasNext()) {MazeCell cell = itr.next();path[cell.getX()][cell.getY()] = VISITED;}display(System.out, path);}public static void main(String[] args) {Maze maze = new Maze();maze.exitMaze(System.out);maze.printPath(System.out);}}6.结果输出Enter a rectangular maze using the following characters: 6-entry9-exit1-wall0-passageEnter one line at a time; end with Ctrl-d;90000110110000000600//构造的迷宫如下111111119000011110111100000110060011111111//开始探路11111111900001111011110000011006001 11111111111111 1900001 1110111 1000001 1006301 11111111111111 1900001 1110111 1000001 1006331 1111111 1111111 1900001 1110111 1000031 1006331 11111111111111 1900001 1110111 1000331 1006331 1111111 1111111 1900001 1110111 1003331 1006331 11111111111111 1900001 1110111 1033331 1006331 1111111111111119000011110111133333110063311111111111111119000011110111133333113063311111111111111119000011110111133333113363311111111//下一步为回溯过程111111119000011110111133333113363311111111111111119000011113111133333113363311111111111111119030011113111133333113363311111111111111119033011113111133333113363311111111111111119033311113111133333113363311111111//下一步为回溯过程111111119333311113111133333113363311111111SuccessPath:111111119330011113111100300110060011111111。
《数据结构课程设计:迷宫》实验报告任务分配:●程序员:主要任务:负责整体的算法设计以及程序的主要源代码的编写。
●测试员:主要任务:负责在程序员每完成一个阶段对程序进行挑错,测试主程序并对实验结果进行整理分析,最后完成实验报告的第三、四部分即测试结果与分析探讨的内容。
●文档员:主要任务:负责对程序及界面的美观提出改善意见,查找程序的小漏洞,负责撰写实验报告的第一、二部分即实验内容简介与算法描述的内容。
同时完成整个文档的整合,使整篇报告排版、文字风格统一。
一、简介图的遍历就是从指定的某个顶点(称其为初始点)出发,按照一定的搜索方法对图中的所有顶点各做一次访问过程。
根据搜索方法不同,遍历一般分为深度优先搜索遍历和广度优先搜索遍历。
本实验中用到的是广度优先搜索遍历。
即首先访问初始点v i,并将其标记为已访问过,接着访问v i的所有未被访问过的邻接点,顺序任意,并均标记为已访问过,以此类推,直到图中所有和初始点v i有路径相通的顶点都被访问过为止。
鉴于广度优先搜索是将所有路径同时按照顺序遍历,直到遍历出迷宫出口,生成的路径为最短路径。
因此我们采用了广度优先搜索。
无论是深度优先搜索还是广度优先搜索,其本质都是将图的二维顶点结构线性化的过程,并将当前顶点相邻的未被访问的顶点作为下一个顶点。
广度优先搜索采用队列作为数据结构。
本实验的目的是设计一个程序,实现手动或者自动生成一个n×m矩阵的迷宫,寻找一条从入口点到出口点的通路。
具体实验内容如下:选择手动或者自动生成一个n×m的迷宫,将迷宫的左上角作入口,右下角作出口,设“0”为通路,“1”为墙,即无法穿越。
假设一只老鼠从起点出发,目的为右下角终点,可向“上、下、左、右、左上、左下、右上、右下”8个方向行走。
如果迷宫可以走通,则用“■”代表“1”,用“□”代表“0”,用“☆”代表行走迷宫的路径。
输出迷宫原型图、迷宫路线图以及迷宫行走路径。
如果迷宫为死迷宫,则只输出迷宫原型图。
迷宫求解一.问题描述对迷宫问题的求解过程实际就是从入口开始,一步一步地走到出口的过程。
基本要求:输入一个任意大小的迷宫数据,用递归和非递归两种方法求出一条走出迷宫的路径,并将路径输出。
二.设计思路在本程序中用两种方法求解迷宫问题-非递归算法和递归算法。
对于非递归算法采用回溯的思想,即从入口出发,按某一方向向前探索,若能走通,并且未走过,则说明某处可以到达,即能到达新点,否则试探下一方向;若所有的方向均没有通路,或无路可走又返回到入口点。
在求解过程中,为了保证在到达某一点后不能向前继续行走(无路)时,能正确返回前一点以便继续从下一个方向向前试探,则需要用一个栈保存所能到达的没一点的下标及该点前进的方向,然后通过对各个点的进出栈操作来求得迷宫通路。
对于递归算法,在当前位置按照一定的策略寻找下个位置,在下个位置又按照相同的策略寻找下下个位置…;直到当前位置就是出口点,每一步的走法都是这样的。
随着一步一步的移动,求解的规模不断减小;如果起始位置是出口,说明路径找到,算法结束,如果起始位置的四个方向都走不通,说明迷宫没有路径,算法也结束。
另外,为了保证迷宫的每个点都有四个方向可以试探,简化求解过程,将迷宫四周的值全部设为1,因此将m行n列的迷宫扩建为m+2行,n+2列,同时用数组来保存迷宫阵列。
三.数据结构设计在迷宫阵列中每个点都有四个方向可以试探,假设当前点的坐标(x,y),与其相邻的四个点的坐标都可根据该点的相邻方位而得到,为了简化问题,方便求出新点的坐标,将从正东开始沿顺时针进行的这四个方向的坐标增量放在一个结构数组move[4]中,每个元素有两个域组成,其中x为横坐标增量,y为纵坐标增量,定义如下:typedef struct{int x,y;}item;为到达了某点而无路可走时需返回前一点,再从前一点开始向下一个方向继续试探。
因此,还要将从前一点到本点的方向压入栈中。
栈中的元素由行、列、方向组成,定义如下:typedef struct{int x,y,d;}DataType;由于在非递归算法求解迷宫的过程中用到栈,所以需定义栈的类型,本程序中用的是顺序栈,类型定义如下;typedef struct{DataType data[MAXSIZE];int top;}SeqStack, *PSeqStack;四.功能函数设计(1)函数PSeqStack Init_SeqStack()此函数实现对栈的初始化工作。
(2)函数Empty_SeqStack(PSeqStack S)此函数用于判断栈是否为空。
(3)函数Push_SeqStack (PSeqStack S, DataType x) 此函数实现入栈操作。
(4)函数Pop_SeqStack(PSeqStack S ,DataType *x)此函数实现出栈操作。
(5)函数Destory_Seqstack(PSeqStack *S)此函数执行栈的销毁操作,释放内存空间。
(6)函数mazepath(int maze[][n+2],item move[],int x0,int y0) 此函数实现对迷宫问题的非递归算法求解。
在求解过程中需调用上面定义的关于栈的一系列函数(栈的初始化,判空,入栈,出栈,栈的销毁),进而求得迷宫路径。
(7)函数path(int maze[][n+2],item move[],int x,int y,int step)此函数实现对迷宫问题的递归算法求解。
(8)函数print_way(int maze[][n+2],item move[])此函数用于在递归算法求解迷宫后输出求解后的结果,即打印迷宫路径。
(9)函数copy(int maze[][n+2],int ms[][n+2])此函数的作用是复制一下输入的原始迷宫序列,因为本程序是通过菜单选择求解迷宫的实现方式,将非递归算法和递归算法放在一起通过菜单选择实现,在调用完一种算法后,为保证调用另一种算法时原始迷宫序列未改变,所以需调用此函数来原始迷宫序列备份一下。
(10)主函数main()定义变量,实现迷宫的输入操作,通过菜单选择求解迷宫路径的实现方法,调用相关函数。
(11)系统功能总体模块(a)栈的初始化(b)判栈空函数(c)入栈(d)出栈(e)销毁栈(f)非递归算法求解迷宫函数(g)递归算法求解迷宫函数(h)打印递归算法求解迷宫的路径函数(i)复制原始迷宫阵列函数(j)主函数五.编码实现#include<stdio.h>#include<stdlib.h>#define m 6#define n 8#define MAXSIZE 100typedef struct{int x,y;}item;item move[4];typedef struct{int x,y,d;}DataType;typedef struct{DataType data[MAXSIZE];int top;}SeqStack, *PSeqStack;PSeqStack Init_SeqStack() //栈的初始化{PSeqStack S;S=(PSeqStack)malloc(sizeof(SeqStack));if (S)S->top=-1;return S;}int Empty_SeqStack(PSeqStack S) //判栈空{if (S->top==-1)return 1;elsereturn 0;}int Push_SeqStack (PSeqStack S, DataType x) //入栈{if (S->top==MAXSIZE-1)return 0; //栈满不能入栈else{S->top++;S->data[S->top]=x;return 1;}}int Pop_SeqStack(PSeqStack S ,DataType *x) //出栈{if (Empty_SeqStack ( S ) )return 0; //栈空不能出栈else{*x=S->data[S->top];S->top--;return 1;}}void Destory_Seqstack(PSeqStack *S) //销毁栈{if(*S)free(*S);*S=NULL;return;}int mazepath(int maze[][n+2],item move[],int x0,int y0) //非递归算法求解迷宫{PSeqStack S;DataType temp;int x,y,d,i,j;temp.x=x0;temp.y=y0;temp.d=-1;S=Init_SeqStack();if(!S){printf("栈初始化失败!");return (0);}Push_SeqStack (S, temp);while(!Empty_SeqStack(S)){Pop_SeqStack(S ,&temp);x=temp.x;y=temp.y;d=temp.d+1;while(d<4){i=x+move[d].x;j=y+move[d].y;if(maze[i][j]==0){temp.x=x;temp.y=y;temp.d=d;Push_SeqStack (S, temp);x=i;y=j;maze[x][y]=-1;if(x==m&&y==n){printf("\n非递归算法求解的迷宫路径为(顺序为从出口到入口输出):\n");while(!Empty_SeqStack(S)){Pop_SeqStack(S,&temp);printf("(%d %d) <- ",temp.x,temp.y);}printf("\n\n................................................................................\n");Destory_Seqstack(&S);return 1;}elsed=0;}elsed++;}}Destory_Seqstack(&S);return 0;}int path(int maze[][n+2],item move[],int x,int y,int step) //递归算法求解迷宫{int i;step++;maze[x][y]=step;if(x==m&&y==n)return 1;for(i=0;i<4;i++){if(maze[x+move[i].x][y+move[i].y]==0)if(path(maze,move,x+move[i].x,y+move[i].y,step))return 1;}step--;maze[x][y]=0;return 0;}void print_way(int maze[][n+2],item move[]) //打印递归算法求解迷宫的路径{int i,j;if(path(maze,move,1,1,1)){printf("\n找到路径的矩阵形式输出如下:\n");for(i=0;i<m+2;i++){for(j=0;j<n+2;j++)printf("%d ",maze[i][j]);printf("\n");}printf("\n");printf("递归算法求解的迷宫路径为(顺序为从入口到出口输出):\n");for(i=0;i<m+2;i++)for(j=0;j<n+2;j++)if(maze[i][j]>1)printf("(%d %d) -> ",i,j);printf("\n\n................................................................................\n");}elseprintf("无法找到路径!\n");}void copy(int maze[][n+2],int ms[][n+2]) //复制原始迷宫序列函数{for(int i=0;i<m+2;i++){for(int j=0;j<n+2;j++)ms[i][j]=maze[i][j];}}void main(){int maze[m+2][n+2];item move[4];int i,j,Q;printf("请输入迷宫序列:\n");for(i=0;i<m+2;i++){for(j=0;j<n+2;j++)scanf("%d",&maze[i][j]);}printf("\n");move[0].x=0;move[0].y=1;move[1].x=1;move[1].y=0;move[2].x=0;move[2].y=-1;move[3].x=-1;move[3].y=0;printf("\n");int mase1[m+2][n+2];copy(maze,mase1);printf("********************************走迷宫******************************************\n");printf("\n");printf("1. 非递归形式走迷宫\n");printf("2. 递归形式走迷宫\n");printf("3. 退出\n");printf("********************************求解方式****************************************\n");while(1){printf("\n请选择(选择0退出)::");scanf("%d",&Q);switch(Q){case 1:mazepath(maze,move,1,1);break;case 2:print_way(mase1,move);break;case 0:exit(0);}}}六.运行与测试七.总结在这个课程设计中,遇到的主要问题是选择了一种实现方法后,在选择另一种时不会输出结果,但是当我把这两个程序分开调试时都会出现结果,结果还是正确的,后来经过分析知道原来是调用完一种方法后,原来输入的迷宫序列可能被改变了,因此,又增加了一个复制原始迷宫序列的函数,对原始序列进行了保存,然后在调用时就出现结果了。