《數據結構與算法分析》課程設計——迷宮問題

中國礦業大學信控學院算法

 

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 }
相關文章
相關標籤/搜索