《数据结构与算法分析》课程设计——迷宫问题

中国矿业大学信控学院

 

一、 问题描述

 

问题中迷宫可用方阵[m,n]表示,0表示能通过,1表示不能通过。若要从从左上角[1,1]进入迷宫,设计算法,寻求一条从右下角
[m,n] 出去的路径。我们用递增的数来代表寻找出口方向与步数,用-2来代表寻找过程中找错的路径。

二、 需求分析

 

需要先创建一个迷宫,在开始后就开始搜寻,当一个点周围有0点(改点并不是以搜寻过的点),那么到这里继续往下搜,如果搜到尽头那么就要倒回去,在搜寻倒回去的周围还有为搜寻过得0点,因此需要一个存储算法,要满足后入先出,那么就是栈,利用栈就可以满足需求。

三、 算法分析

 

1.    首先先定义栈,本问题中,不需要在中间插入与弹出,插入与弹出操作均在栈头,因此我们利用顺序栈。

并且该栈与实验课的栈不同,因为要满足实际需求,所以我们需要定义步数以及改点所在的位置以及临近路径的位置在我们栈中,具体操作如下。

 1 //记录通道块在迷宫矩阵当中的横、纵坐标
 2 struct Position {
 3     int x;
 4     int y;
 5 };
 6
 7 //放入栈当中的通道块元素
 8 struct SElement {
 9     int ord;//记录步数
10     Position p;//记录位置
11     int di;//记录下一次测试这一路径的临近路径的位置
12 };
13
14 struct MyStack {
15     SElement* base;
16     SElement* top;
17     int stacksize;
18 };

2.    栈的一些列基础操作,例如创建栈,判断栈是否为空,取栈顶元素,获取栈长,入栈,出栈。上述操作类似学校实验中基本操作,这里不在叙述,详见附录中全部代码。

3.    接下来创建迷宫,这里迷宫利用数组来生成,x轴为n,y轴为m

n为18,m为15。生成方法简单,这里不在叙述,详见附录中全部代码。

4.    接下来定义如何走这个迷宫,考虑我们用0作为通道,1作为墙壁,那么搜寻一个点的上下左右0就是可以通过,1就是不能通过。利用以下循环来完成目标:

步骤1:挪到0处的点并且把刚才位置入栈,让改点改为步数,让步数加一,然后继续搜索其上下左右(除去刚才通过的点)如果有0,继续执行步骤1。

步骤2:如果周围的点无0(除去刚才已经通过的点),让改点改为-2,那么就出栈,把路径调到刚才的那个点,并且把步数减一,然后执行步骤1,搜寻其上下左右(出去刚才走错的点以及入这个点之前的点)。

直至入栈点是终点那么退出循环。

代码如下:

 1 do
 2     {
 3         if (Pass(curp))
 4         {
 5             FootPrint(curp, curStep);//可走就在迷宫里面留下足迹
 6 //创建一个栈元素,存储可行路径的相关值
 7             SElement e;
 8             e.di = 1;// 下一个路块为这一个路块的右边的路块
 9             e.ord = curStep;
10             e.p.x = curp.x;
11             e.p.y = curp.y;
12             Push(&path, e);//将路径块入栈
13 if (curp.x == m - 2 && curp.y == n - 2) break; //如果被压入的路径块到了迷宫的终点就退出循环
14             //找到下一个被试块
15 curp = NextPosition(curp, 1);//找到前一个被试块东面的路径块作为被试块
16             curStep++;//被探索的步数加一
17         }
18         else//如果当前被试路径不能够通过的话
19         {
20             if (!IsStackEmpty(&path))
21             {
22                 SElement e;
23                 Pop(&path, &e);
24                 curStep--;
25                 //将这一段所有的周围路径都已经被测试过的路径从栈中清除
26                 while (e.di == 4 && !IsStackEmpty(&path)) {
27                     MarkPrint(e.p);
28                     Pop(&path, &e);
29                     curStep--;
30                 }
31                 //如果当前栈顶还有未被测试的路径就测试剩余的周围路径
32                 if (e.di<4)
33                 {
34                     curp = NextPosition(e.p, e.di + 1);
35                     e.di++;
36                     curStep++;
37                     Push(&path, e);
38                 }
39             }
40         }
41     } while (!IsStackEmpty(&path));

5.    在定义上述代码中如何去搜寻,按照从右到下再到左再到上的方法搜寻。代码如下:

 1 //按顺时针方向从右开始寻找矩阵当中某一个位置的临近位置
 2 Position NextPosition(Position now, int direction)
 3 {
 4     Position next;
 5     int x = now.x;
 6     int y = now.y;
 7     switch (direction)
 8     {
 9         //右
10         case 1: {
11         next.x = x;
12         next.y = y + 1;
13         break;
14         }
15             //下
16         case 2: {
17         next.x = x + 1;
18         next.y = y;
19         break;
20         }
21             //左
22         case 3: {
23         next.x = x;
24         next.y = y - 1;
25         break;
26         }
27             //上
28         case 4:{
29         next.x = x - 1;
30         next.y = y;
31         break;
32         }
33         default:break;
34     }
35     return next;
36}

6.    定义是否可以通过函数,是就返回ture不是就返回false。代码如下:

 1 //辅助函数考察当前路径能否通过
 2 bool Pass(Position posi)
 3 {
 4     //只有路径所在位置的数字为0的是可以走的
 5     if (Maze[posi.x][posi.y] == 0)
 6     {
 7         return true;
 8     }
 9     return false;
10 }

7.    定义是入栈和出栈时如何修改迷宫数组中的值。代码如下:

 1 //改变改点为步骤数
 2 void FootPrint(Position p, int step)
 3 {
 4     Maze[p.x][p.y] = step;
 5 }
 6
 7 //路径不可走的话就留下-2的标记
 8 void MarkPrint(Position p)
 9 {
10     Maze[p.x][p.y] = -2;
11}

8.    定义打印迷宫函数,这个就是遍历整个数组,过程简单这里不在叙述,见附录中全部代码。

四、 结论

编辑ing...

五、 参考文献

[1] 严蔚敏,吴伟民——《数据结构》清华大学出版社2004.2.1

六、 附录

完整代码如下:

  1 #include <stdio.h>
  2 #include <malloc.h>
  3 #define STACK_INIT_SIZE 100
  4 #define STACKINCREMENT 10
  5
  6 //记录通道块在迷宫矩阵当中的横、纵坐标
  7 struct Position {
  8     int x;
  9     int y;
 10 };
 11
 12 //放入栈当中的通道块元素
 13 struct SElement {
 14     int ord;//记录步数
 15     Position p;//记录位置
 16     int di;//记录下一次测试这一路径的临近路径的位置
 17 };
 18
 19 struct MyStack {
 20     SElement* base;
 21     SElement* top;
 22     int stacksize;
 23 };
 24
 25 //创建一个栈如果创建成功则返回1,否则就返回0
 26 int InitStack(MyStack* s)
 27 {
 28     s->base = (SElement*)malloc(STACK_INIT_SIZE * sizeof(SElement));//为栈分配初始空间
 29     if (!s->base) return 0;
 30     s->top = s->base;//设定为空栈
 31     s->stacksize = STACK_INIT_SIZE;
 32     return 1;
 33 }
 34
 35 //判断栈是否为空,如果是空的就返回0,否则就返回1
 36 int IsStackEmpty(MyStack* s)
 37 {
 38     if (s->top == s->base) return true;
 39     return false;
 40 }
 41
 42 //获取栈顶元素,如果栈为空就返回0 否则就返回1
 43 int GetTop(MyStack* s, SElement* e)
 44 {
 45     if (IsStackEmpty(s)) return 0;
 46     e = s->top - 1;
 47     return 1;
 48 }
 49
 50 //获取栈的长度,并且通过程序返回
 51 int StackLength(MyStack* s)
 52 {
 53     return s->top - s->base;
 54 }
 55
 56 //插入元素e为新的栈顶元素,插入成功则返回1,否则返回0
 57 int  Push(MyStack* s, SElement e)
 58 {
 59     if (s->top - s->base >= STACK_INIT_SIZE)
 60     {
 61         s->base = (SElement*)realloc(s->base, (s->stacksize + STACKINCREMENT) * sizeof(SElement));
 62         if (!s->base) return 0;
 63         s->top = s->base + s->stacksize;
 64         s->stacksize += STACKINCREMENT;
 65     }
 66     *(s->top) = e;
 67     s->top++;
 68     return 1;
 69 }
 70
 71 //弹出栈顶元素赋值给e弹出成功返回1,弹出失败返回0
 72 int Pop(MyStack* s, SElement* e)
 73 {
 74     if (IsStackEmpty(s)) return 0;
 75     *e = *(s->top - 1);
 76     s->top--;
 77     return 1;
 78 }
 79
 80 //定义墙元素为1 可走路径为0 已知路径为curStep 不能够通过的路径为-2
 81 #define m 15
 82 #define n 18
 83 int Maze[m][n] = {  { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },
 84                     { 1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1 },
 85                     { 1,0,1,1,1,0,1,0,0,1,0,1,1,1,1,1,0,1 },
 86                     { 1,0,1,1,1,0,1,0,1,1,0,1,0,1,1,0,0,1 },
 87                     { 1,0,0,0,0,0,1,0,1,1,0,1,0,0,0,0,1,1 },
 88                     { 1,1,1,1,0,0,1,0,1,1,0,1,1,1,1,0,1,1 },
 89                     { 1,1,1,0,0,1,1,0,1,1,0,0,0,1,1,1,1,1 },
 90                     { 1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,0,0,1 },
 91                     { 1,1,1,0,0,0,0,0,0,0,1,1,0,1,1,0,1,1 },
 92                     { 1,0,0,1,1,1,1,1,1,0,1,1,0,1,0,0,1,1 },
 93                     { 1,1,0,0,0,0,0,0,0,0,1,0,0,1,0,1,1,1 },
 94                     { 1,0,0,1,0,1,0,1,0,0,1,1,0,0,0,1,1,1 },
 95                     { 1,1,0,1,0,1,0,1,1,1,0,0,0,1,1,1,1,1 },
 96                     { 1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1 },
 97                     { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 } };
 98
 99 //辅助函数考察当前路径能否通过
100 bool Pass(Position posi)
101 {
102     //只有路径所在位置的数字为0的是可以走的
103     if (Maze[posi.x][posi.y] == 0)
104     {
105         return true;
106     }
107     return false;
108 }
109
110 //按顺时针方向从右开始寻找矩阵当中某一个位置的临近位置
111 Position NextPosition(Position now, int direction)
112 {
113     Position next;
114     int x = now.x;
115     int y = now.y;
116     switch (direction)
117     {
118         //右
119     case 1: {
120         next.x = x;
121         next.y = y + 1;
122         break;
123     }
124             //下
125     case 2: {
126         next.x = x + 1;
127         next.y = y;
128         break;
129     }
130             //左
131     case 3: {
132         next.x = x;
133         next.y = y - 1;
134         break;
135     }
136             //上
137     case 4:
138     {
139         next.x = x - 1;
140         next.y = y;
141         break;
142     }
143     default:break;
144     }
145     return next;
146 }
147
148 //改变改点为步骤数
149 void FootPrint(Position p, int step)
150 {
151     Maze[p.x][p.y] = step;
152 }
153
154 //路径不可走的话就留下-2的标记
155 void MarkPrint(Position p)
156 {
157     Maze[p.x][p.y] = -2;
158 }
159
160 //打印出迷宫矩阵
161 void Display_migong()
162 {
163     for (int i = 0; i<m; i++)
164     {
165         for (int j = 0; j<n; j++)
166         {
167             if (Maze[i][j]<0)
168                 printf("%d ", Maze[i][j]);
169             else if (Maze[i][j]<10)
170                 printf("%d  ", Maze[i][j]);
171             else
172                 printf("%d ", Maze[i][j]);
173         }
174         printf("\n");
175     }
176 }
177
178 int main()
179 {
180
181     //迷宫程序主体
182     MyStack  path;//记录路径的栈
183     InitStack(&path);//初始化路径数组
184     Position curp;//当前被试位置
185     Display_migong();
186     //初始化当前位置为矩阵入口
187     curp.x = 1;
188     curp.y = 1;
189     int curStep = 1;//被探索的步数
190     do
191     {
192         if (Pass(curp))
193         {
194             FootPrint(curp, curStep);//可走就在迷宫里面留下足迹
195 //创建一个栈元素,存储可行路径的相关值,将这个元素存储到栈当中
196             SElement e;
197             e.di = 1;//下一个路块为这一个路块的右边的路块
198             e.ord = curStep;
199             e.p.x = curp.x;
200             e.p.y = curp.y;
201             Push(&path, e);//将路径块入栈
202 if (curp.x == m - 2 && curp.y == n - 2) break; //如果被压入的路径块到了迷宫的终点就退出循环
203 curp = NextPosition(curp, 1);//找到前一个被试块东面的路径块作为被试块
204             curStep++;//被探索的步数加一
205         }
206         else//如果当前被试路径不能够通过的话
207         {
208             if (!IsStackEmpty(&path))
209             {
210                 SElement e;
211                 Pop(&path, &e);
212                 curStep--;
213                 //将所有的周围路径都已经被测试过的路径从栈中清除
214                 while (e.di == 4 && !IsStackEmpty(&path)) {
215                     MarkPrint(e.p);
216                     Pop(&path, &e);
217                     curStep--;
218                 }
219                 //如果当前栈顶还有未被测试的路径就测试剩余的周围路径
220                 if (e.di<4)
221                 {
222                     curp = NextPosition(e.p, e.di + 1);
223                     e.di++;
224                     curStep++;
225                     Push(&path, e);
226                 }
227             }
228         }
229     } while (!IsStackEmpty(&path));
230     printf("\n");
231     //打印出结果迷宫矩阵
232     Display_migong();
233     return 0;
234 }

原文地址:https://www.cnblogs.com/zhangzhangzhang624531420/p/12181727.html

时间: 2024-08-29 19:33:55

《数据结构与算法分析》课程设计——迷宫问题的相关文章

利用不相交集类制作迷宫游戏(数据结构课程设计——迷宫老鼠)

之前大一的时候有几天闲来无事,为了学习做了一个可以自动生成迷宫,可以寻找最短路径的小游戏,现在整理分享一下 简单介绍: 利用不相交集类考虑一个迷宫的生成,一个简单算法就是从各处的墙壁开始(除入口和出口之外).此时,不断地随机选择一面墙,如果被该墙分割的单元彼此不联通,那么就把这面墙拆掉.重复这个过程直到开始单元和终止单元联通,那么就得到一个迷宫.实际上不断的拆掉墙壁直到每个单元都可以从其他单元到达更好(这会使迷宫产生更多误导的路径). 整理一下迷宫的生成算法就是: (1)将迷宫初始时看成一个一个

数据结构大二课程设计:QT实现线段树

源码以及编译文件下载地址:http://download.csdn.net/detail/zhiyanpianyu1234/9445909#comment 加入了一些小东西,一直觉得课设是做给自己看的,老师怎么看并不重要23333 优化了界面效果,加上学习QT大概用了两个月时间才完成 源码中用了两种计算方法(线段树实际上完全可以绕过去23333) 感谢紫薇画的树,我拿来做背景了,还是蛮好看的(虽然被我ps的很难看) 运行效果:

数据结构——课程设计

  <数据结构课程设计>   课程题目 模拟电话客服管理系统 课程编号 j1620102 学生姓名 吴佳煜 所在专业 信息管理与信息系统 所在班级 信管1133 任课老师 易学明 实习时间 二〇一四年十二月二十五日 设计成绩 老师评语 一.课程设计题目 赵斌是一个信管专业的学生,大学四年顺利毕业了.在毕业季,他也像其他学子一样,投身于求职大军,投出一份又一份求职简历,在苦苦地等待之后,他接到了中国移动通信公司广东分司的面试通知书,通知他于本月1号10点到公司面试.当天,晴空万里,艳阳高照,他身

数据结构课程设计题目四_二叉树

本文出自:http://blog.csdn.net/svitter 题目4:二叉树 给出一颗无线的二叉树.树的每一个结点用一整数对标识.二叉树构造如下 树根被标识为(1, 1): 如果一个结点被标识为(a, b), 则其左孩子被标识为(a+b,b),右孩子被标识为(a, a+b).现在给出某一结点(a, b),求树根到该结点的最短路径,并且同时求出从树根出发向左走和向右走的次数.建议完成人数1人. 注:此处使用了STL_stack库函数,是不允许的,我图方便. //===============

数据结构课程设计

20. 公交线路上优化路径的查询  问题描述 最短路径问题是图论中的一个经典问题,其中的Dijkstra算法一直被认为是图论中的好算法,但有的时候需要适当的调整Dijkstra算法才能完成多种不同的优化路径的查询. 对于某城市的公交线路,乘坐公交的顾客希望在这样的线路上实现各种优化路径的查询.设该城市的公交线路的输入格式为: 线路编号:起始站名(该站坐标):经过的站点1名(该站坐标):经过的站点2名(该站坐标):--:经过的站点n名(该站坐标):终点站名(该站坐标).该线路的乘坐价钱.该线路平均

数据结构_课程设计——最小生成树:室内布线

***************************************转载请注明出处:http://blog.csdn.net/lttree******************************************** 这道课程设计,费不少时间,太麻烦了= =.(明明是能力不够) ~~~~最小生成树:室内布线~~~~ 题目要求: 装修新房子是一项颇为复杂的工程,现在需要写个程序帮助房主设计室内电线的布局. 首先,墙壁上插座的位置是固定的.插座间需要有电线相连,而且要布置的整齐美

数据结构_课程设计——并查集:检查网络

***************************************转载请注明出处:http://blog.csdn.net/lttree******************************************** 这两天做数据结构课程设计,因为以前做过ACM题,感觉还可以,不是很难呀 ~~~~并查集:检查网络~~~~ 题目要求: 给定一个计算机网络以及机器间的双向连线列表,每一条连线允许两端的计算机进行直接的文件传输,其他计算机间若存在一条连通路径,也可以进行间接的文件传

数据结构课程设计题目十二_计算机学院学生会的打印机(优先队列)

本文出自:http://blog.csdn.net/svitter 题目12:计算机学院学生会的打印机(优先队列) 小明抱怨学生会的打印机不符合FIFO的原则,看到很多在他后面来打印的同学比他先打印出来.五分钟前,小明的文件就是下一个候选的,如今小明的文件又排到了后面.学生会的同学给小明解释说,学生会的打印机不是採用传统的队列方式,而是採用一种自定义的优先队列方式:每一个要打印的文件被赋予了一个从1到9的优先级(9最高,1最低).打印规定例如以下: 将队列中要打印的文件f从队列中拿出来: 假设在

《数据结构与算法分析:C语言描述》复习——第十章“算法设计技巧”——Alpha-Beta剪枝

2014.07.08 22:43 简介: “搜索”与“剪枝”几乎是如影随形的.此处的“搜索”指的是带有回溯算法的深度优先搜索. 在之前的“Minimax策略”中我们给出了一个三连棋的程序,运行后你就知道计算一步棋要花多少时间. 为了计算最优的一步棋,我们可能需要递归9万多次.如果毫无疑问这种阶乘式的穷举过程必须通过剪枝来加速. 本篇介绍一种用于Minimax策略的剪枝思路——α-β剪枝. 剪枝的英语是pruning,所以不要想当然说成trimming. 图示: 在上一篇讲解Minimax策略的博