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

中国矿业大学信控学院算法

 

1、 问题描述数组

 

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

 

2、 需求分析函数

 

须要先建立一个迷宫,在开始后就开始搜寻,当一个点周围有0点(改点并非以搜寻过的点),那么到这里继续往下搜,若是搜到尽头那么就要倒回去,在搜寻倒回去的周围还有为搜寻过得0点,所以须要一个存储算法,要知足后入先出,那么就是栈,利用栈就能够知足需求。测试

 

3、 算法分析spa

 

1.    首先先定义栈,本问题中,不须要在中间插入与弹出,插入与弹出操做均在栈头,所以咱们利用顺序栈。设计

而且该栈与实验课的栈不一样,由于要知足实际需求,因此咱们须要定义步数以及改点所在的位置以及临近路径的位置在咱们栈中,具体操做以下。code

 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.    栈的一些列基础操做,例如建立栈,判断栈是否为空,取栈顶元素,获取栈长,入栈,出栈。上述操做相似学校实验中基本操做,这里不在叙述,详见附录中所有代码。blog

 

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

   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.    定义打印迷宫函数,这个就是遍历整个数组,过程简单这里不在叙述,见附录中所有代码。

4、 结论

 

 编辑ing...

 

5、 参考文献

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

 

6、 附录

 

完整代码以下:

  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 }
相关文章
相关标签/搜索