数据结构课程设计_迷宫问题
- 格式:doc
- 大小:366.00 KB
- 文档页数:23
数据结构课程设计迷宫问题求解正文:一、引言在数据结构课程设计中,迷宫问题求解是一个经典且常见的问题。
迷宫问题求解是指通过编程实现在迷宫中找到一条从起点到终点的路径。
本文将详细介绍如何用数据结构来解决迷宫问题。
二、问题分析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.选择合适的编程语言和开发环境。
数据结构程序设计(迷宫问题)数据结构程序设计(迷宫问题)一、引言迷宫问题是计算机科学中常见的问题之一,它涉及到了数据结构的设计和算法的实现。
本文将介绍迷宫问题的定义、常见的解决算法和程序设计思路。
二、问题定义迷宫问题可以描述为:给定一个迷宫,迷宫由若干个连通的格子组成,其中有些格子是墙壁,有些格子是路径。
任务是找到一条从迷宫的起点(通常是左上角)到终点(通常是右下角)的路径。
三、基本数据结构1.迷宫表示:迷宫可以使用二维数组来表示,数组中的每个元素代表一个格子,可以用0表示路径,用1表示墙壁。
2.坐标表示:可以使用二维坐标表示迷宫中的每一个格子,使用(x, y)的形式表示。
四、算法设计1.深度优先搜索算法:深度优先搜索算法可以用来解决迷宫问题。
算法从起点开始,尝试向四个方向中的一个方向前进,如果可以移动则继续向前,直到到达终点或无法继续移动。
如果无法继续移动,则回溯到上一个节点,选择另一个方向继续搜索,直到找到一条路径或者所有路径都已经探索完毕。
2.广度优先搜索算法:广度优先搜索算法也可以用来解决迷宫问题。
算法从起点开始,先将起点加入队列,然后不断从队列中取出节点,并尝试向四个方向中的一个方向移动,将新的节点加入队列。
直到找到终点或者队列为空,如果队列为空则表示无法找到路径。
五、程序设计思路1.深度优先搜索算法实现思路:a) 使用递归函数来实现深度优先搜索算法,参数为当前节点的坐标和迷宫数据结构。
b) 判断当前节点是否为终点,如果是则返回成功。
c) 判断当前节点是否为墙壁或已访问过的节点,如果是则返回失败。
d) 将当前节点标记为已访问。
e) 递归调用四个方向,如果存在一条路径则返回成功。
f) 如果四个方向都无法找到路径,则将当前节点重新标记为未访问,并返回失败。
2.广度优先搜索算法实现思路:a) 使用队列保存待访问的节点。
b) 将起点加入队列,并标记为已访问。
c) 不断从队列中取出节点,尝试向四个方向移动,如果新的节点未被访问过且不是墙壁,则将新的节点加入队列,并标记为已访问。
课题设计1:迷宫求解一. 需求分析:本程序是利用非递归的方法求出一条走出迷宫的路径,并将路径输出。
首先由用户输入一组二维数组来组成迷宫,确认后程序自动运行,当迷宫有完整路径可以通过时,以0和1所组成的迷宫形式输出,标记所走过的路径结束程序;当迷宫无路径时,提示输入错误结束程序。
二、概要设计:1.抽象数据类型定义:ADT Find{数据对象:D={ai?ai ∈ElemSet,i=1,2,…,n,n≥0}数据关系:R1={<ai-1,ai>?ai-1, ai∈D }基本操作:find (&S)初始条件:已初始化栈S,且栈为空操作结果:从栈S中找出相对应的数据关系,并输出结果}ADT Find2. 主程序的流程以及各程序模块之间的调用关系:(1).定义变量i、j、w、z为整形变量(2).输入迷宫二维数组maze(0:m,0:n)(3).调用子程序find ()(4).结束程序三、相应的源程序如下:#include<stdio.h>#include<stdlib.h>typedef enum { ERROR, OK } Status;typedef struct{int row, line;}PosType;typedef struct{int di, ord;PosType seat;}SElemType;typedef struct{SElemType * base;SElemType * top;int stacksize;}SqStack;Status InitStack(SqStack &S);Status Push(SqStack &S,SElemType &a);Status Pop(SqStack &S,SElemType &a);Status StackEmpty(SqStack S);Status MazePath(int maze[12][12],SqStack &S, PosType start, PosType end);void Initmaze(int maze[12][12],int size);void printmaze(int maze[12][12],int size);Status Pass(int maze[12][12],PosType CurPos);void Markfoot(int maze[12][12], PosType CurPos);PosType NextPos(PosType CurPos, int Dir);void printpath(int maze[12][12],SqStack S,int size);void main (void){SqStack S;int size,maze[12][12];for(int n=0;n<10;n++){printf("创建一个正方形迷宫,请输入迷宫尺寸(注意不要大于50):\n");scanf("%d",&size);if(size<1 || size>10){printf("输入错误!");return;}Initmaze(maze,size);printmaze(maze,size);PosType start,end;printf("输入入口行坐标和列坐标:");scanf("%d",&start.row);scanf("%d",&start.line);printf("输入出口行坐标和列坐标:");scanf("%d",&end.row);scanf("%d",&end.line);if(MazePath(maze,S,start,end))printpath(maze,S,size);else printf("找不到通路!\n\n");}}Status MazePath(int maze[12][12],SqStack &S, PosType start, PosType end){PosType curpos;int curstep;SElemType e;InitStack(S);curpos = start;curstep = 1;do {if (Pass(maze,curpos)){Markfoot(maze,curpos);e.di =1;e.ord = curstep;e.seat= curpos;Push(S,e);if (curpos.row==end.row && curpos.line==end.line)return OK;curpos = NextPos(curpos, 1);curstep++;}else{if (!StackEmpty(S)){Pop(S,e);while (e.di==4 && !StackEmpty(S)) {Markfoot(maze,e.seat);Pop(S,e);}if (e.di<4){e.di++;Push(S, e);curpos = NextPos(e.seat, e.di);}}}} while (!StackEmpty(S));return ERROR;}void Initmaze(int maze[12][12],int size){char select;printf("选择创建方式A:自动生成B:手动创建\n");label:scanf("%c",&select);if(select=='a'||select=='A'){for(int i=0;i<size+2;i++)maze[0][i]=1;for( i=1;i<size+1;i++){maze[i][0]=1;for(int j=1;j<size+1;j++)maze[i][j]=rand()%2;maze[i][size+1]=1;}for(i=0;i<size+2;i++)maze[size+1][i]=1;}else if(select=='b'||select=='B'){printf("按行输入%d*%d数据,0代表可通,1代表不可通(每行以Enter结束):\n",size,size);for(int i=0;i<size+2;i++)maze[0][i]=1;for( i=1;i<size+1;i++){maze[i][0]=1;for(int j=1;j<size+1;j++)scanf("%d",&maze[i][j]);maze[i][size+1]=1;}for(i=0;i<size+2;i++)maze[size+1][i]=1;}else if(select=='\n')goto label;else printf("输入错误!");}void printmaze(int maze[12][12],int size){printf("\n\n");printf("显示所建的迷宫(#表示外面的墙):\n");for(int i=0;i<size+2;i++)printf("%c ",'#');printf("\n");for(i=1;i<size+1;i++){printf("%c ",'#');for(int j=1;j<size+1;j++){printf("%d ",maze[i][j]);}printf("%c",'#');printf("\n");}for(i=0;i<size+2;i++)printf("%c ",'#');printf("\n");}void printpath(int maze[12][12],SqStack S,int size){printf("\n\n通路路径为:\n");SElemType * p=S.base;while(p!=S.top){maze[p->seat.row][p->seat.line]=2;p++;}for(int i=0;i<size+2;i++)printf("%c ",'#');printf("\n");for(i=1;i<size+1;i++){printf("%c ",'#');for(int j=1;j<size+1;j++){if(maze[i][j]==2) printf("%c ",'0');else printf(" ");}printf("%c",'#');printf("\n");}for(i=0;i<size+2;i++)printf("%c ",'#');printf("\n\n"); }Status Pass(int maze[12][12],PosType CurPos){if (maze[CurPos.row][CurPos.line]==0)return OK;else return ERROR;}void Markfoot(int maze[12][12],PosType CurPos){maze[CurPos.row][CurPos.line]=1;}PosType NextPos(PosType CurPos, int Dir){PosType ReturnPos;switch (Dir){case 1:ReturnPos.row=CurPos.row;ReturnPos.line=CurPos.line+1;break;case 2:ReturnPos.row=CurPos.row+1;ReturnPos.line=CurPos.line;break;case 3:ReturnPos.row=CurPos.row;ReturnPos.line=CurPos.line-1;break;case 4:ReturnPos.row=CurPos.row-1;ReturnPos.line=CurPos.line;break;}return ReturnPos;}Status InitStack(SqStack &S){S.base=(SElemType *)malloc(100*sizeof(SElemType));if(!S.base)return ERROR;S.top=S.base;S.stacksize=100;return OK;}Status Push(SqStack &S,SElemType &a){*S.top++=a;return OK;}Status Pop(SqStack &S,SElemType &a){if(S.top==S.base)return ERROR;a=*--S.top;return OK;}Status StackEmpty(SqStack S){if(S.top==S.base)return OK;return ERROR;}以下为测试数据:输入一个矩阵,例如:1 0 0 1 10 0 1 1 11 0 0 0 10 1 0 1 11 1 0 0 0输入入口行坐标和列坐标:1 2输入出口行坐标和列坐标:5 5通路路径为:课题设计3:joseph环一. 需求分析:利用单向循环链表存储结构模拟此过程,按照出列的顺序输出各个人的编号。
目录第一部分需求分析第二部分详细设计第三部分调试分析第四部分用户手册第五部分测试结果第六部分附录第七部分参考文献一、需求分析1、对于给定的一个迷宫,给出一个出口和入口,找一条从入口到出口的通路,并把这条通路显示出来;如果没有找到这样的通路给出没有这样通路的信息。
2、可以用一个m×n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。
设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。
3、编写一个求解迷宫的非递归程序。
求得的通路以三元组(i,j,d)的形式输出,其中:(i,j)指示迷宫中的一个坐标,d表示走到下一坐标的方向。
4、由于迷宫是任意给定的,所以程序要能够对给定的迷宫生成对应的矩阵表示,所以程序的输入包括了矩阵的行数、列数、迷宫内墙的个数、迷宫内墙的坐标、所求的通路的入口坐标、出口坐标。
二、详细设计1、计算机解迷宫通常用的是“穷举求解“方法,即从人口出发,顺着某一个方向进行探索,若能走通,则继续往前进;否则沿着原路退回,换一个方向继续探索,直至出口位置,求得一条通路。
假如所有可能的通路都探索到而未能到达出口,则所设定的迷宫没有通路。
可以二维数组存储迷宫数据,通常设定入口点的下标为(1,1),出口点的下标为(n,n)。
为处理方便起见,可在迷宫的四周加一圈障碍。
对于迷宫中任一位置,均可约定有东、南、西、北四个方向可通。
2、如果在某个位置上四个方向都走不通的话,就退回到前一个位置,换一个方向再试,如果这个位置已经没有方向可试了就再退一步,如果所有已经走过的位置的四个方向都试探过了,一直退到起始点都没有走通,那就说明这个迷宫根本不通。
3、所谓"走不通"不单是指遇到"墙挡路",还有"已经走过的路不能重复走第二次",它包括"曾经走过而没有走通的路"。
显然为了保证在任何位置上都能沿原路退回,需要用一个"后进先出"的结构即栈来保存从入口到当前位置的路径。
数据结构课程设计-迷宫问题正文:一、引言本文档旨在设计一个解决迷宫问题的数据结构课程项目。
迷宫问题是一个典型的寻路问题,要求从起点出发,在迷宫中找到一条路径到达终点。
迷宫由多个房间组成,这些房间之间通过门相连。
二、问题描述迷宫问题包含以下要素:1.迷宫的拓扑结构:迷宫由多个房间和门组成,每个房间有四面墙壁,每面墙壁可能有门或者是封闭的。
迷宫的起点和终点是预先确定的。
2.寻路算法:设计一个算法,在迷宫中找到一条从起点到终点的路径。
路径的选择标准可以是最短路径、最快路径或者其他约束条件。
3.可视化展示:实现一个可视化界面,在迷宫中展示起点、终点、路径,用于直观地演示解决方案。
三、设计思路1.数据结构设计:选择合适的数据结构来表示迷宫和路径,例如使用二维数组或者图来表示迷宫的拓扑结构,使用栈或队列来辅助寻路算法的实现。
2.寻路算法设计:可以使用深度优先搜索、广度优先搜索、Dijkstra算法、A算法等经典算法来实现寻路功能。
根据实际需求选择最合适的算法。
3.可视化展示设计:使用图形界面库(如Tkinter、Qt等)创建迷宫展示窗口,并实时更新迷宫的状态、路径的变化。
可以通过颜色、动画等方式增加交互性。
四、实现步骤1.创建迷宫:根据预设的迷宫大小,使用数据结构来创建对应的迷宫数据。
2.设定起点和终点:在迷宫中选择起点和终点的位置,将其标记出来。
3.寻路算法实现:根据选择的寻路算法,在迷宫中找到一条路径。
4.可视化展示:使用图形界面库创建窗口,并将迷宫、起点、终点、路径等信息展示出来。
5.更新迷宫状态:根据算法实现的过程,实时更新迷宫中的状态,并将路径显示在迷宫上。
附件:1.代码实现:包含迷宫创建、寻路算法实现和可视化展示的源代码文件。
2.演示视频:展示项目实际运行效果的视频文件。
法律名词及注释:1.数据结构:指在计算机科学中定义和组织数据的方式和方式的基础设施。
2.寻路算法:用于解决寻找路径的问题的算法。
课程设计报告课程名称数据结构课程设计课题名称迷宫问题专业班级学号姓名指导教师2012年6月9日课程设计任务书课程名称数据结构课程设计课题迷宫问题专业班级学生姓名学号指导老师审批任务书下达日期:2012年6月9日任务完成日期: 2012年6月16日一、设计内容与设计要求1.设计内容:1)问题描述以一个M*N的长方阵表示迷宫,0和1分别表示迷宫中的通路和墙壁。
设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出米有通路的结论。
2)基本要求a.实现一个以链表作存储结构的栈类型,然后编写一个求解迷宫的非递归程序。
求得的通路以三元组(i,j,d)的形式输出,其中:(i,j)指示迷宫中的一个坐标,d表示走到下一个坐标的方向。
b。
编写递归形式的算法,求得迷宫中所有可能的通路。
3)测试数据迷宫的测试数据如下:左上角(1,1)为入口,右下角(8,9)为出口。
4)实现提示计算机解迷宫通常用的是“穷举求解”方法,即从入口出发,顺着某一个方向进行探索,若能走通,则继续往前进;否则,沿着原路退回,换一个方向继续探索,直至出口位置,求得一条通路。
假如所有可能的通路都探索到而未能到达出口,则设定的迷宫没有通路。
可以二维数组存储迷宫数据,通常设定入口点的下标为(1,1),出口点的下标为(m,n)。
为处理方便起见,可在迷宫的四周加一圈障碍。
对于迷宫中任一位置,均可约定有东、南、西、北四个方向可通.2.设计要求:●课程设计报告规范1)需求分析a.程序的功能.b.输入输出的要求。
2)概要设计a.程序由哪些模块组成以及模块之间的层次结构、各模块的调用关系;每个模块的功能。
b.课题涉及的数据结构和数据库结构;即要存储什么数据,这些数据是什么样的结构,它们之间有什么关系等。
3)详细设计a。
采用C语言定义相关的数据类型.b。
写出各模块的类C码算法.c.画出各函数的调用关系图、主要函数的流程图.4)调试分析以及设计体会a.测试数据:准备典型的测试数据和测试方案,包括正确的输入及输出结果和含有错误的输入及输出结果。
目录第一部分需求分析第二部分详细设计第三部分调试分析第四部分用户手册第五部分测试结果第六部分附录第七部分参考文献一、需求分析1、对于给定的一个迷宫.给出一个出口和入口.找一条从入口到出口的通路.并把这条通路显示出来;如果没有找到这样的通路给出没有这样通路的信息。
2、可以用一个m×n的长方阵表示迷宫.0和1分别表示迷宫中的通路和障碍。
设计一个程序.对任意设定的迷宫.求出一条从入口到出口的通路.或得出没有通路的结论。
3、编写一个求解迷宫的非递归程序。
求得的通路以三元组(i.j.d)的形式输出.其中:(i.j)指示迷宫中的一个坐标.d表示走到下一坐标的方向。
4、由于迷宫是任意给定的.所以程序要能够对给定的迷宫生成对应的矩阵表示.所以程序的输入包括了矩阵的行数、列数、迷宫内墙的个数、迷宫内墙的坐标、所求的通路的入口坐标、出口坐标。
二、详细设计1、计算机解迷宫通常用的是“穷举求解“方法.即从人口出发.顺着某一个方向进行探索.若能走通.则继续往前进;否则沿着原路退回.换一个方向继续探索.直至出口位置.求得一条通路。
假如所有可能的通路都探索到而未能到达出口.则所设定的迷宫没有通路。
可以二维数组存储迷宫数据.通常设定入口点的下标为(1.1).出口点的下标为(n.n)。
为处理方便起见.可在迷宫的四周加一圈障碍。
对于迷宫中任一位置.均可约定有东、南、西、北四个方向可通。
2、如果在某个位置上四个方向都走不通的话.就退回到前一个位置.换一个方向再试.如果这个位置已经没有方向可试了就再退一步.如果所有已经走过的位置的四个方向都试探过了.一直退到起始点都没有走通.那就说明这个迷宫根本不通。
3、所谓"走不通"不单是指遇到"墙挡路".还有"已经走过的路不能重复走第二次".它包括"曾经走过而没有走通的路"。
显然为了保证在任何位置上都能沿原路退回.需要用一个"后进先出"的结构即栈来保存从入口到当前位置的路径。
迷宫求解一.问题描述对迷宫问题的求解过程实际就是从入口开始,一步一步地走到出口的过程。
基本要求:输入一个任意大小的迷宫数据,用递归和非递归两种方法求出一条走出迷宫的路径,并将路径输出。
二.设计思路在本程序中用两种方法求解迷宫问题-非递归算法和递归算法。
对于非递归算法采用回溯的思想,即从入口出发,按某一方向向前探索,若能走通,并且未走过,则说明某处可以到达,即能到达新点,否则试探下一方向;若所有的方向均没有通路,或无路可走又返回到入口点。
在求解过程中,为了保证在到达某一点后不能向前继续行走(无路)时,能正确返回前一点以便继续从下一个方向向前试探,则需要用一个栈保存所能到达的没一点的下标与该点前进的方向,然后通过对各个点的进出栈操作来求得迷宫通路。
对于递归算法,在当前位置按照一定的策略寻找下个位置,在下个位置又按照相同的策略寻找下下个位置…;直到当前位置就是出口点,每一步的走法都是这样的。
随着一步一步的移动,求解的规模不断减小;如果起始位置是出口,说明路径找到,算法结束,如果起始位置的四个方向都走不通,说明迷宫没有路径,算法也结束。
另外,为了保证迷宫的每个点都有四个方向可以试探,简化求解过程,将迷宫四周的值全部设为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()此函数实现对栈的初始化工作。
摘要设计一个简单迷宫程序,从入口出发找到一条通路到达出口。
编制程序给出一条通过迷宫的路径或报告一个“无法通过”的信息。
首先实现一个以链表作存储结构的栈类型,然后编写一个求解迷宫的非递归程序。
用“穷举求解”方法,即从入口出发,顺着某一个方向进行探索,若能走通,则继续往前进;否则沿着原路退回,换一个方向继续探索,直至出口位置,求得一条通路。
假如所有可能的通路都探索到而未能到达出口,则所设定的迷宫没有通路。
可以用二维数组存储迷宫数据,通常设定入口点的下标为(1,1),出口点的下标为(n,n)。
为处理方便起见,可在迷宫的四周加一障碍。
对于迷宫任一位置,均可约定有东、南、西、北四个方向可通。
关键词:迷宫;栈;链表;二维数组目录1 问题描述 (1)2 需求分析 (1)3 概要设计 (1)3.1抽象数据类型定义 (1)3.2模块划分 (2)4 详细设计 (2)4.1数据类型的定义 (2)4.2主要模块的算法描述 (3)5 测试分析 (6)6 课程设计总结 (7)参考文献 (7)附录(源程序清单) (8)1 问题描述迷宫是一个M行N列的0-1矩阵,其中0表示无障碍,1表示有障碍。
设入口为(1,1)出口为(M,N)每次移动只能从一个无障碍的单元移到其周围8个方向上任一无障碍的单元,编制程序给出一条通过迷宫的路径或报告一个“无法通过”的信息。
2 需求分析(1)首先实现一个以链表作存储结构的栈类型,然后编写一个求解迷宫的非递归程序。
求得的通路以三元组(i,j,d)的形式输出,其中:(i,j)指示迷宫中的一个坐标,d表示走到下一坐标的方向。
否则报告一个无法通过的信息。
(2)建立InitStack函数,用于构造一个空栈。
(3)建立DestroyStack函数,用于销毁栈。
(4)建立Pop函数,用于删除栈顶元素,返回栈顶元素的值。
(5)建立Push函数,用于插入新的栈顶元素。
(6)建立NextPos函数,用于定位下一个位置。
课程设计(论文)任务书软件学院软件工程+电子商务2009 专业 2 班一、课程设计(论文)题目迷宫问题二、课程设计(论文)工作自 2010年 12月 27日起至 2011年 1月 2 日止三、课程设计(论文) 地点: 创新大楼实训中心四、课程设计(论文)内容要求:1.本课程设计的目的(1)巩固和加深对数据结构基本知识的理解,提高综合运用课程知识的能力。
(2)使学生掌握软件设计的基本内容和设计方法,并培养学生进行规范化软件设计的能力。
(3)使学生掌握使用各种计算机资料和有关参考资料,提高学生进行程序设计的基本能力。
2.课程设计的任务及要求1)基本要求:(1)对系统进行功能模块分析、控制模块分析;(2)系统设计要能完成题目所要求的功能;(3)编程简练,可用,尽可能的使系统的功能更加完善和全面;(4)说明书、流程图要清楚;(5)提高学生的论文写作能力;(6)特别要求自己独立完成;2)创新要求:在基本要求达到后,可进行创新设计,如改善算法性能、友好的人机界面。
3)课程设计论文编写要求(1)要按照书稿的规格打印与写课程设计论文(2)论文包括目录、正文、小结、参考文献、附录等(3)课程设计论文装订按学校的统一要求完成4)课程设计进度安排内容天数地点构思及收集资料 1 图书馆编码与调试 3 实验室撰写论文 1 图书馆、实验室学生签名:20011 年1 月3日课程设计(论文)评审意见(1)基本算法(20分):优()、良()、中()、一般()、差();(2)设计分析(20分):优()、良()、中()、一般()、差();(3)调试分析(20分):优()、良()、中()、一般()、差();(4)论文内容(20分):优()、良()、中()、一般()、差();(5)答辩分析(20分):优()、良()、中()、一般()、差();(6)格式规范性及考勤是否降等级:是()、否()评阅人:职称:讲师2011 年1月4日目录一、需求分析 (1)二、概要设计 (2)三、详细设计 (5)四、调试分析及测试 (15)五、个人工作及创新 (18)六、小结 (19)参考文献 (20)一、需求分析1.选题理由本次课设我选择了迷宫问题,迷宫求解是数据结构课程的一个经典问题,迷宫问题要求寻找一条从入口到出口的路径。
通常用的是“穷举求解”的方法。
为了保证在任何位置上都能原路退回,显然需要用一个后进先出的结构来保存从入口到当前位置的路径。
因此,在求解迷宫通路的算法中要应用“栈”的思想。
对于栈的内容在整个学期的学习中我也有了一定的了解,所以选择了迷宫这一经典问题作为本次课设的内容。
2.基本原理分析迷宫问题通常是用“穷举求解”方法解决,即从入口出发,顺着某一个方向进行探索,若能走通,则继续往前走;否则沿着原路退回,换一个方向继续探索,直至出口位置,求得一条通路。
假如所有可能的通路都探索到而未能到达出口,则所设定的迷宫没有通路。
栈是一个后进先出的结构,可以用来保存从入口到当前位置的路径。
以二维数组存储迷宫数据,通常设定入口点的下标为(1,1),出口点的下标为(n,n)。
为处理方便起见,在迷宫的四周加一圈障碍。
对于迷宫任何一个位置,均约定东、南、西、北四个方向可通。
3.功能要求(1)以一个二维数组Maze[m+2][n+2]表示迷宫,其中:Maze[0][j]和Maze[m+1][j](0<=j<=n+1)及Maze[i][0]和Maze[i][n+1] (0<=i<=m+1)为做外层的一圈障碍。
数组中以0表示通路,1表示障碍,限定迷宫的大小为:m,n<=10。
(2)用户需用文件的形式输入迷宫的数据:文件中第一行的数据为迷宫的行数m和列数n;从第2行至第m+1行(每行n个数)为迷宫值,用0,1输入,同行中的两个数字之间用空白字符相隔。
(3)迷宫的入口位置和出口位置可由用户随时设定。
(4)若设定的迷宫存在通路,则以长方阵形式将迷宫及其通路输出到标准输出文件上,其中字符“#”表示障碍,“*”表示路径,“@”表示曾途经该位置但不能到达出口,其余位置用空格符表示。
若设定迷宫不存在通路则报告相应信息(5)本程序只求出一条成功的通路。
(6)程序执行的命令为:1,创建迷宫;2,求解迷宫;3,输出迷宫的解。
二、概要设计1、数据结构及其抽象数据类型的定义。
(1)栈的抽象数据类型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。
DestroyStack(&S)初始条件:栈S已存在。
操作结果:销毁栈S。
ClearStack(&S)初始条件:栈S已存在。
操作结果:将S清为空栈。
StackLength(S)初始条件:栈S已存在。
操作结果:返回栈S的长度。
StackEmpty(S)初始条件:栈S已存在。
操作结果:若S为空栈,则返回TRUE,否则返回FALSE。
GetTop(S,&e)初始条件:栈S已存在。
操作结果:若栈S不空,则以e返回栈顶元素。
Push(&S, e)初始条件:栈S已存在。
操作结果:在栈S的栈顶插入新的栈顶元素e。
Pop(&S,&e)初始条件:栈S已存在。
操作结果:删除S的栈顶元素,并以e返回其值。
StackTraverse(S,visit())初始条件:栈S已存在。
操作结果:从栈底到栈顶依次对S中的每个元素调用函数visit()。
} ADT Stack(2)迷宫的抽象数据类型ADT maze{数据对象:D={ai,j| ai,j∈{ '','#','@','*'},0<=i<=m+1,0<=j<=n+1,m,n<=10}数据关系:R={ROW,COL}基本操作:InitMaze(&M,a,row,col)初始条件:二维数组a[row+2][col+2]已存在,其中自第1行至第row+1行,每行中自第1列至第col+1列的元素已有值,并且以值0表示通路,以值1表示障碍。
操作结果:构成迷宫的字符型数组,以空白字符表示通路,以字符‘#’表示障碍,并在迷宫四周加上一圈障碍。
MazePath(&M)初始条件:迷宫M已被赋值。
操作结果:若迷宫M中存在一条通路,则按以下规定改变迷宫M的状态:以字符’*’表示路径上的位置,字符‘@’表示“死胡同”,否则迷宫的状态不变。
PrintMaze(M)初始条件:迷宫M已存在。
操作结果:以字符形式输出迷宫。
} ADT maze2、整体框架本程序包含三个模块(1)栈模块——实现栈抽象数据类型(2)迷宫模块——实现迷宫抽象数据类型(3)主程序模块:void mian(){初始化;Do{接受命令;处理命令;}while(命令!=“退出”);}各模块之间的调用关系如图一:图一:调用关系图函数的调用关系图反映了程序的层次结构如图二:图二:函数的调用关系图三、详细设计源程序:#include <stdio.h>#include <stdlib.h>#include <string.h>#define MAXLEN 10//迷宫包括外墙最大行列数目#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0typedef int Status;// 坐标位置类型typedef struct{int r,c;} PosType;//迷宫中r行c列的位置//迷宫类型typedef struct {int r;int c;char arr[MAXLEN][MAXLEN];//可取' ','*','@','#' }MazeType;typedef struct{//int step; // 当前位置在路径上的“序号”PosType seat; //当前的坐标位置int di; //往下一坐标位置的方向}SElemType;//结点类型typedef struct NodeType{SElemType data;NodeType *next;}NodeType,*LinkType;//栈类型typedef struct {LinkType top;int stacksize;}SqStack;PosType start;PosType end;MazeType maze;bool found;//创建栈Status InitStack(SqStack &S){S.top=(LinkType)malloc(sizeof(NodeType)); S.top->next=NULL;S.stacksize=0;return OK;}//进栈Status Push(SqStack &S,SElemType &e){LinkType p;p=(NodeType*)malloc(sizeof(NodeType));p->data=e;p->next=S.top;S.top=p;S.stacksize++;return OK;}//判断是否为栈空Status StackEmpty(SqStack S){if(S.top->next==NULL) return OK;return ERROR;}//出栈Status Pop(SqStack &S,SElemType &e){LinkType p;if(StackEmpty(S)) return ERROR;p=S.top;e=p->data;S.top=S.top->next;S.stacksize--;free(p);return OK;}//销毁栈Status DestroyStack(SqStack &S){LinkType p;while(S.top!=NULL){p=S.top;S.top=S.top->next;free(p);}//一个一个删除if(S.top==NULL) return OK;else return ERROR;}//曾走过但不是通路标记并返回OKStatus MarkPrint(MazeType &maze,PosType curpos){maze.arr[curpos.r][curpos.c]='@';//"@"表示曾走过但不通 return OK;}//曾走过而且是通路标记并返回OKStatus FootPrint(MazeType &maze,PosType curpos){maze.arr[curpos.r][curpos.c]='*';//"*"表示可通return OK;}//选择下一步的方向PosType NextPos(PosType &curpos,int i){PosType cpos;cpos=curpos;switch(i){ //1.2.3.4分别表示东,南,西,北方向case 1 : cpos.c+=1;break;case 2 : cpos.r+=1;break;case 3 : cpos.c-=1;break;case 4 : cpos.r-=1;break;}return cpos;}//判断当前位置是否可通Status Pass(MazeType &maze, PosType curpos){if(maze.arr[curpos.r][curpos.c]==' ') return TRUE;else return FALSE;}//创建迷宫//按照用户输入的二维数组(0或1),设置迷宫maze的初值,包括加上边缘一圈的值void InitMaze(MazeType &maze, char a[MAXLEN][MAXLEN], int row, int col){maze.r=row;maze.c=col;for(int i=0;i<=col+1;i++){a[0][i]='1';a[row+1][i]='1';}for(i=0;i<=row+1;i++){a[i][0]='1';a[i][col+1]='1';}for(i=0;i<=maze.r+2;i++){for(int j=0;j<maze.c+2;j++){if(a[i][j]=='1') maze.arr[i][j]='#';else maze.arr[i][j]=' ';}}}//求迷宫路径的伪码算法:Status MazePath(MazeType &maze,PosType start,PosType end){//求解迷宫maze中,从入口start到出口end的一条路径,若存在,返回TRUE,否则返回FALSEPosType curpos;SqStack S;SElemType e;InitStack(S);curpos=start;//设定“当前位置”为“入口位置”//curstep=1; //探索第一步found=false;do{if(Pass(maze,curpos)){//当前位置可以通过,即是未曾走到过的通道块留下足迹FootPrint(maze,curpos);//做可以通过的标识//e.step=curstep;e.seat=curpos;e.di=1; //为栈顶元素赋值Push(S,e); //加入路径if(curpos.r==end.r && curpos.c==end.c) found=true;//如果到达终点返回trueelse{curpos=NextPos(curpos,1);//下一位置是当前位置的东邻 }}else //当前位置不能通过if(!StackEmpty(S)){Pop(S,e);while(e.di==4 && !StackEmpty(S)){MarkPrint(maze,e.seat); //留下不能通过的标记Pop(S,e);}if(e.di<4){e.di++; //换下个方向Push(S,e); //curpos=NextPos(e.seat,e.di); //进行探索}}}while(!StackEmpty(S)&&!found);DestroyStack(S);return found;}//将标记路径信息的迷宫(字符型方阵)输出到终端(包括外墙)void PrintMaze(MazeType &maze){for(int i=0;i<=maze.r+2;i++){for(int j=0;j<=maze.c+2;j++){printf(" %c",maze.arr[i][j]);//输出迷宫}printf("\n");}}//系统初始化void Initialization(){system("cls");printf(" welcome to the game!!! "); printf("\n************************************************");printf("\n*创建迷宫--c 执行迷宫--m 输出迷宫--p 退出--q*");printf("\n************************************************");printf("\n\n 操作:-");}//读入操作命令符,显示提示信息void ReadCommand(char &cmd){do{if(cmd=='c'){printf("\n******************************************");printf("\n*选择操作 :执行迷宫--m *");printf("\n* 退出--:q *");printf("\n******************************************");printf("\n\n 操作:-");}else if(cmd=='m'){printf("\n******************************************");printf("\n*选择操作 :输出迷宫--p *");printf("\n* 退出--:q *");printf("\n******************************************");printf("\n\n 操作:-");}else if(cmd=='p'){printf("\n******************************************");printf("\n*选择操作 :执行迷宫--c *");printf("\n* 退出--:q *");printf("\n******************************************"); printf("\n\n 操作:-");}cmd=getchar();}while(!(cmd=='c'||cmd=='m'||cmd=='p'||cmd=='q'));}//解释cmd--具体执行void Interpre(char cmd){switch(cmd){case 'c':{int rnum, cnum, i=0,m=1,n=1;char a2[MAXLEN][MAXLEN];char input[1];char data[1000];printf("\n请输入迷宫数据文件名!\n");scanf("%s",input);FILE *fp;fp=fopen(input,"r");if(!fp){printf("\n不能打开文件\n");break;}while(!feof(fp)){fscanf(fp,"%s",&data[i]);if(i==0){rnum=(int)data[i]-(int)'0';}if(i==1){cnum=(int)data[i]-(int)'0';}if(i>=2){if(n>cnum){m++;n=1;}a2[m][n]=data[i];n++;}i++;}fclose(fp);InitMaze(maze, a2, rnum, cnum);printf("\n迷宫建立完成!!\n");break;}case 'm':{printf("\n请输入迷宫入口的坐标,以空格为间隔:--"); scanf("%d %d",&start.r,&start.c);printf("\n请输入迷宫出口的坐标,以空格为间隔:--"); scanf("%d %d",&end.r,&end.c);MazePath(maze, start, end);break;}case 'p':{if(found){printf("\n求解迷宫的结果如下--\n");PrintMaze(maze);}else printf("\n找不到路径!\n");}}}void main(){char cmd;Initialization();do{ReadCommand(cmd); //读入一个操作符命令Interpre(cmd); //解释执行命令操作符}while(cmd!='q');}四、调试分析及测试1、调试分析:(1)本程序有一个核心算法,即求迷宫的路径,在调试的时候,出现了两个问题:没有想到要用‘@’记号,导致迷宫走不出来;没有设置‘found’,不知何时跳出。