C++ 数据结构 迷宫问题

上传人:少*** 文档编号:53813579 上传时间:2022-02-11 格式:DOC 页数:23 大小:369KB
收藏 版权申诉 举报 下载
C++ 数据结构 迷宫问题_第1页
第1页 / 共23页
C++ 数据结构 迷宫问题_第2页
第2页 / 共23页
C++ 数据结构 迷宫问题_第3页
第3页 / 共23页
资源描述:

《C++ 数据结构 迷宫问题》由会员分享,可在线阅读,更多相关《C++ 数据结构 迷宫问题(23页珍藏版)》请在装配图网上搜索。

1、课程设计(论文)任务书 软件 学 院 软件工程+电子商务2009 专 业 2 班 一、课程设计(论文)题目 迷宫问题 二、课程设计(论文)工作自 2010 年 12月 27 日起至 2011 年 1月 2 日止 三、课程设计(论文) 地点: 创新大楼实训中心 四、课程设计(论文)内容要求: 1.本课程设计的目的 (1)巩固和加深对数据结构基本知识的理解,提高综合运

2、用课程知识的能力。 (2)使学生掌握软件设计的基本内容和设计方法,并培养学生进行规范化软 件设计的能力。 (3)使学生掌握使用各种计算机资料和有关参考资料,提高学生进行程序设 计的基本能力。 2.课程设计的任务及要求 1)基本要求: (1)对系统进行功能模块分析、控制模块分析; (2)系统设计要能完成题目所要求的功能; (3)编程简练,可用,尽可能的使系统的功能更加完善和全面; (4)说明书、流程图要清楚; (5)提高学生的论文写作能力; (6)特别要求自己独立完成; 2)创新要求: 在基本要求达到后,可进行创新设计,如改善算法性能、友好的人机界面。

3、 3)课程设计论文编写要求 (1)要按照书稿的规格打印与写课程设计论文 (2)论文包括目录、正文、小结、参考文献、附录等 (3)课程设计论文装订按学校的统一要求完成 4)课程设计进度安排 内容 天数 地点 构思及收集资料 1 图书馆 编码与调试 3 实验室 撰写论文 1 图书馆、实验室 学生签名: 200

4、11 年 1 月 3日 课程设计(论文)评审意见 (1)基本算法 (20分):优( )、良( )、中( )、一般( )、差( ); (2)设计分析 (20分):优( )、良( )、中( )、一般( )、差( ); (3)调试分析 (20分):优( )、良( )、中( )、一般( )、差( ); (4)论文内容 (20分):优( )、良( )、中( )、一般( )、差( ); (5)答辩分析 (20分):优( )、良( )、中( )、一般( )、差( ); (6)格式规范性及考勤是否降等级:是( )、否( ) 评阅人: 职称: 讲师

5、 2011 年 1月4日 目录 一、 需求分析 1 二、 概要设计 2 三、 详细设计 5 四、 调试分析及测试 15 五、 个人工作及创新 18 六、 小结 19 参考文献 20 数据结构课程设计 一、 需求分析 1.选题理由 本次课设我选择了迷宫问题,迷宫求解是数据结构课程的一个经典问题, 迷宫问题要求寻找一条从入口到出口的路径。通常用的是“穷举求解”的方法。为了保证在任何位置上都能原路退回,显然需要用一个后进先出的结构来保存从入口到当前位置的路径。因此,在求解迷宫通路的算法中要应用“栈”的思想。对于栈的内容在整个学期的学

6、习中我也有了一定的了解,所以选择了迷宫这一经典问题作为本次课设的内容。 2.基本原理分析 迷宫问题通常是用“穷举求解”方法解决,即从入口出发,顺着某一个方向进行探索,若能走通,则继续往前走;否则沿着原路退回,换一个方向继续探索,直至出口位置,求得一条通路。假如所有可能的通路都探索到而未能到达出口,则所设定的迷宫没有通路。栈是一个后进先出的结构,可以用来保存从入口到当前位置的路径。 以二维数组存储迷宫数据,通常设定入口点的下标为(1,1),出口点的下标为(n,n)。为处理方便起见,在迷宫的四周加一圈障碍。对于迷宫任何一个位置,均约定东、南、西、北四个方向可通。

7、 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)若设定的迷宫存在通路,则以长方阵形式将迷宫及

8、其通路输出到标准输出文件上,其中字符“#”表示障碍,“*”表示路径,“@”表示曾途经该位置但不能到达出口,其余位置用空格符表示。若设定迷宫不存在通路则报告相应信息 (5)本程序只求出一条成功的通路。 (6)程序执行的命令为:1,创建迷宫;2,求解迷宫;3,输出迷宫的解。 二、 概要设计 1、 数据结构及其抽象数据类型的定义。 (1)栈的抽象数据类型 ADT Stack{ 数据对象:D={ai| ai∈CharSet,i=1,2…n,n>=0} 数据关系:R1={| ai-1, ai∈D,i=2,…n} 基本操作: InitStack(&S) 操作

9、结果:构造一个空栈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。

10、 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][

11、col+2]已存在,其中自第1行至第row+1行,每行中自第1列至第col+1列的元素已有值,并且以值0表示通路,以值1表示障碍。 操作结果:构成迷宫的字符型数组,以空白字符表示通路,以字符‘#’表示障碍,并在迷宫四周加上一圈障碍。 MazePath(&M) 初始条件:迷宫M已被赋值。 操作结果:若迷宫M中存在一条通路,则按以下规定改变迷宫M的状态:以字符’*’表示路径上的位置,字符‘@’表示“死胡同”,否则迷宫的状态不变。 PrintMaze(M) 初始条件:迷宫M已存在。 操作结果:以字符形式输出迷宫。 } ADT maze   2、整体框架 本程序包含三个模块

12、(1)栈模块——实现栈抽象数据类型 (2)迷宫模块——实现迷宫抽象数据类型 (3)主程序模块: void mian() {    初始化;   Do{ 接受命令; 处理命令; }while(命令!=“退出”); } 各模块之间的调用关系如图一: 图一:调用关系图 函数的调用关系图反映了程序的层次结构如图二: 图二 :函数的调用关系图 三、 详细设计 源程序: #include

13、dio.h> #include #include #define MAXLEN 10//迷宫包括外墙最大行列数目 #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0   typedef int Status; // 坐标位置类型  typedef struct{     int r,c; } PosType;//迷宫中r行c列的位置 //迷宫类型  typedef struct {      int r;      int c;      ch

14、ar arr[MAXLEN][MAXLEN];//可取' ','*','@','#' }MazeType;     typedef struct{ //int step; // 当前位置在路径上的“序号”    PosType seat; //当前的坐标位置    int di; //往下一坐标位置的方向 }SElemType;  //结点类型 typedef struct NodeType{    SElemType data;    NodeType *next; }NodeType,*LinkType; //栈类型  typedef struct {

15、    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,SElemT

16、ype &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,SElemTyp

17、e &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;     

18、  free(p);    }//一个一个删除    if(S.top==NULL) return OK;    else return ERROR; }   //曾走过但不是通路标记并返回OK Status MarkPrint(MazeType &maze,PosType curpos) {  maze.arr[curpos.r][curpos.c]='@';//"@"表示曾走过但不通  return OK; }   //曾走过而且是通路标记并返回OK Status FootPrint(MazeType &maze,PosType curpos) {   ma

19、ze.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

20、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的初值,包括加上边缘

21、一圈的值 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

22、++){       for(int j=0;j

23、 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;          //为栈顶元素赋值

24、      Push(S,e); //加入路径    if(curpos.r==end.r && curpos.c==end.c) found=true;//如果到达终点返回true      else{           curpos=NextPos(curpos,1);//下一位置是当前位置的东邻       }    }   else   //当前位置不能通过      if(!StackEmpty(S)){          Pop(S,e);          while(e.di==4 && !StackEmpty(S)){             Mar

25、kPrint(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 fou

26、nd; }   //将标记路径信息的迷宫(字符型方阵)输出到终端(包括外墙) 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

27、"); printf("     welcome to the game!!!       "); printf("\n************************************************"); printf("\n*创建迷宫--c 执行迷宫--m 输出迷宫--p  退出--q*"); printf("\n************************************************"); printf("\n\n    操作:-"); }   //读入操作命令符,显示提示信息

28、 void ReadCommand(char &cmd) {  do{    if(cmd=='c')    {     printf("\n******************************************");     printf("\n*选择操作 :执行迷宫--m     *");     printf("\n* 退出--:q           *");     printf("\n******************************************");     printf("\n\n  操作:-");    }    e

29、lse if(cmd=='m'){     printf("\n******************************************");     printf("\n*选择操作 :输出迷宫--p          *");     printf("\n* 退出--:q        *");     printf("\n******************************************");     printf("\n\n 操作:-");    }     else if(cmd=='p'){     pri

30、ntf("\n******************************************");     printf("\n*选择操作 :执行迷宫--c          *");     printf("\n*          退出--:q       *");     printf("\n******************************************");     printf("\n\n          操作:-");    }   cmd=getchar(); }while(!(cmd=='c'||cmd=='m'||cmd=='p'|

31、|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)    {

32、     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]=dat

33、a[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);    M

34、azePath(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);    

35、   //解释执行命令操作符 }while(cmd!='q'); } 四、 调试分析及测试 1、调试分析: (1)本程序有一个核心算法,即求迷宫的路径,在调试的时候,出现了两个问题:没有想到要用‘@’记号,导致迷宫走不出来;没有设置‘found’,不知何时跳出。 (2)原本栈的元素e中除了di—往下一坐标位置的方向和seat—当前的坐标位置,还有一个step—当前位置在路径上的序号,后来发现step没什么用,就删掉了。 (3)函数ReadCommand中,cmd=get

36、char();的位置找不准,最后是试出来的。 (4)调试的时候多次出现,没有错误,但是dos环境下就是执行不起来,所以采用了一些输出变量,判断到底是哪里出了问题。  (5)本程序中三个主要的算法:InitMaze,MazePath和MarkPrint的时间复杂度均为O(m*n), 本程序的空间复杂度也为O(m*n)(栈所占最大空间) 2、 使用说明和运行结果: (1)首先以文件形式输入迷宫数据,如图三: 图三 (2)进入演示程序后,会出现以下界面如图四:  图四 (3) 进入“创建迷宫”的命令后,即提示输入迷宫数据的文件名,结束符为“回车符”,该命令

37、执行之后输出“迷宫建立完成”,且输出下面可执行的操作。如图五: 图五 (4) 进入“执行迷宫”的命令后,即提示输入迷宫入口,出口的坐标,结束符为“回车符”,该命令执行之后表示迷宫路径已寻找完成或未找到路径。请注意:若迷宫中存在路径,执行此命令后,迷宫状态已经改变,若要重复执行此命令,需重新输入迷宫数据。如图六: 图六 (5) 进入“输出迷宫”的命令后,即输出迷宫求出路径之后的状态。‘#’表示障碍,‘@’ 表示曾走过但不通,‘*’表示路径。如图七: 图七 (6) 进入“退出”的命令后,按任意键结束。如图八: 图八 3

38、、 缺点与改进: (1) 在定义函数Mazepath的时候,开始的循环语句的结束条件不对,没有出路时,导致一直出现了不正确的结果,最后没有新位置入栈,则返回上一个位置,否则没有路径。 (2) 只是以文件形式输入迷宫 ,如果迷宫数据量大时,要先建好文件还是很浪费时间,如果以随机产生函数自动产生迷宫会更好 。 五、 个人工作及创新 为了准备这次课程设计我查找了很多的资料,对于迷宫问题的求解中迷宫的产生方式有很多的不同,有的是直接输入迷宫,有的是用文件输入,有的是随机函数产生,我的课设是参考了用文件输入的方法,这样做相比直接输入迷宫操作要更简单。当然用随机函数产生迷宫 比如用: for

39、(i = 0; i < MAX_ROW; i++) for(j = 0; j < MAX_COL; j++) { maze[i][j] = (int) (rand() % 2); } maze[1][0] = 1; /* start point */ maze[MAX_ROW - 1][MAX_COL - 2] = 1; /* end point */ } 这样产生迷宫要更加的方便。结果也有不确定性,可能可以有通路也可能没有。 对于迷宫的求解都是采用的“穷举求解”的方法,用到了一些栈的知识。 把以前学过的栈的基本操作实际应用了一番也使有了更加清楚

40、的认识。 在求解迷宫的算法中,先设定当前位置的初值为入口位置,然后 Do{ 若当前位置可通, 则{将当前位置插入栈顶; 若该位置是出口位置,则结束; 否则切换当前位置的东邻方块为新的当前位置; } 否则{ 若栈不为空且栈顶位置尚有其它方向未被探索, 则设定新的当前位置为延顺时针方向旋转找到的栈顶位置的下 一相邻块; 若栈不空但栈顶位置四周均不通, 则{删去栈顶位置; 若栈不为空,则重新测试新的栈顶位置, 直至找到一

41、个可通的相邻块或出栈至栈空;} } } 求解迷宫的算法大概就是这么个思路。 六、 小结 要能很好的掌握编程,仅仅通过几个简单的程序的编写是无法达成的,更需要的是大量的积累和深入研究才可能。在程序的编写中也不能一味的向已有的程序进行模仿,而要自己去探索,去寻找最好的解决方法,只有带着问题去反复实践,才能更熟练的掌握和运用,当然,对现有的程序也要多去接触,因为有些程序是我们在短时间内无法想出来的,我们也应该去参考别人的作品,这样可以节约时间获得更多的知识。最重要的是持之以恒,要经常性的复习原来接触到的程序,这样才能保证我们有足够的经验去面对程序问题。 参考文献 [1]. 严蔚敏,吴伟民数据结构(C语言版).清华大学出版社.2007 [2]. 严蔚敏,数据结构题集(C语言版).清华大学出版社.2007 [3]. 谭浩强 ,C程序设计(第四版).清华大学出版社.2007 19

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

相关资源

更多
正为您匹配相似的精品文档
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!