1. 程式人生 > >利用棧資料結構徹底搞定走迷宮案例解析(並非最短路徑)

利用棧資料結構徹底搞定走迷宮案例解析(並非最短路徑)

**先上迷宮圖
這裡寫圖片描述
迷宮資料圖我們分0 1 -1 三種可能 0表示可以走白色表示 1表示障礙物 -1表示已經走過
這裡寫圖片描述
方位規則設定:
這裡寫圖片描述
方位也就是我們下面的di的取值為0 1 2 3 這四個方位 表示當前格子可行走的方位
迷宮演算法分析:
這裡寫圖片描述
剛開始的時候我們是有迷宮起點也就是(i,j)是當前起點方塊
並且還沒有找到當前方塊的下一個行走方位,我們根據上面的介紹我們知道方位根據順時針開始標號為0 1 2 3,剛好是個十字架。因此這個時候我們還沒有下步方位的話就設定di = -1; 表示還沒有下個行走路線。
然後我們把當前方塊入棧 也就是i , j -1
這裡寫圖片描述

如果我們找到了當前方塊的下個行走方位對應的方塊,那麼我們就把當前方塊的方位給di儲存。繼續把下個行走方塊入棧。

但是路不是一帆風順的。我們在走的時候也許當前方塊附近全部是障礙物也可以啊,那麼我們怎麼辦,如果你進了死衚衕咋辦,肯定是回到以前的路,並且從沒有走的一個出口繼續走。那麼原先走過的路我們怎麼去找,計算機和我們人不同,你不儲存以前走過的路,是不會像人一樣自動回到過去的路的,我們這個是用了棧資料結構已經把走過的全部方塊入棧了,那麼我們想回退就把當前走不通的路出棧就可以啊,這樣下次出棧就是上次走的方塊,這個時候我們就可以以當前方塊尋找其他方位有沒有通路的情況。當然既然我已經把入棧過的方塊出棧了,那麼我們是不是要標誌一下設定為0呢,這個意思就表示下次也許我用其他路徑是可以走的。
記住我假如把當前行走的方塊入棧後,我會把當前方塊對應的值設定為-1 表示這個方塊已經走了,不能在走了。
大家主要學習思路即可

// 利用棧資料結構走迷宮.cpp: 定義控制檯應用程式的入口點。
#include "stdafx.h"
#define  MaxSize 64   //64就夠了後面的路徑最多把除了牆以外的全部存進來
#define  M 8          //地圖行
#define  N 8          //地圖列
//全域性變數地圖陣列  我們在外面一層設定為1是牆。  規則0表示可以行走的方塊 1是障礙物 
//後面我們還會設定地圖的值為-1標誌我們已經走過,以免重複走進入死迴圈
int MG[M + 2][N + 2] =
{
    { 1,1,1,1,1,1,1,1,1,1 },
    { 1,0,0,1
,0,0,1,0,1,1 }, { 1,0,0,0,0,1,0,0,1,1 }, { 1,0,0,0,0,1,0,1,1,1 }, { 1,1,1,1,0,0,0,0,1,1 }, { 1,0,0,0,0,0,1,0,0,1 }, { 1,0,1,1,0,0,0,0,0,1 }, { 1,0,0,0,0,1,1,0,1,1 }, { 1,0,0,1,0,1,0,0,0,1 }, { 1,1,1,1,1,1,1,1,1,1 } }; //地宮格子對應的資料型別設計 typedef struct { int i; //當前方塊的行號 int j; //當前方塊的列號 int di; //是下一可行走相鄰方位的方位號 可取 0 1 2 3 }Box; //迷宮對應的棧資料結構型別設計 typedef struct { Box data[MaxSize]; //可以用來儲存我們的行走路徑點或者叫可以走的白色方塊資料 int top; //棧頂指標 } StType; //定義順序棧型別 //迷宮資料型別設計 我們假如迷宮的行和列是M = 8,N = 8 //我們還會在外面設計一層牆因此加上2側的圍牆陣列行的元素個數是M+2 //我們規定MG[x][y] = 0表示這個格子可以行走,為1表示是障礙物 //MG[x][y] = -1,表示當前格子已經走過 //用棧求一條走迷宮的路徑演算法 起點start(xi,yi)->end(xe,ye) //迷宮陣列MG[M+2][N+ 2] bool MGPath(int xi, int yi, int xe, int ye) { //定義需要用到的一些初始化變數 find用來標識我們是不是找到了當前方塊走向下個方塊:規則0沒有找到 1找到 int i, j, di, find; //定義棧,並初始化棧資料結構 StType st; st.top = -1; //棧頂指標初始化為-1 //先開始把迷宮起點的方塊資料入棧 st.top++; //入棧前先棧頂指標+1 //開始真正入棧方塊 st.data[st.top].i = xi; st.data[st.top].j = yi; st.data[st.top].di = -1; MG[xi][yi] = -1; //是地圖的陣列資料 表示當前的格子已經走過,下次就不要在走了 //使用迴圈判斷當前入棧的方塊是不是就是我們要的終點資料 while (st.top > -1) //棧裡有方塊才有出棧操作 { //得到棧頂的方塊資料 i = st.data[st.top].i; j = st.data[st.top].j; di = st.data[st.top].di; //比較是不是到了終點 if (i == xe && j == ye) //找到了出口,輸出路徑 { printf("(特別提示由於我們的路徑是用棧儲存,因此輸出的路徑是從終點到起點)\n迷宮路徑如下:\n"); int k = 0; //用一個死迴圈來輸出我們的迷宮行走方塊路徑座標 while (true) { if (st.top == -1) break; //當棧為空的時候就表示沒有方塊資料了 直接退出即可 k++; //就是用換行用 沒有其他作用 //輸出方塊對應地圖中的座標 printf("\t(%d,%d)", st.data[st.top].i, st.data[st.top].j); if (k% 5 == 0) //每輸出5個方塊換一行 { printf("\n"); } st.top--; //由於棧頂方塊路徑已經輸出,那麼就出棧當前的一個方塊,讓指標指向下個方塊路徑繼續迴圈輸出 } printf("\n"); //換行 return true; //找到了一條路徑就退出迴圈 } //開始尋找當前方塊的下個可走的方塊是什麼 find = 0; //初始化為沒有找到 //注意di初始是-1的 因為還沒有找到下個方位 while (di < 4 && find == 0) //為設麼加find必須== 0這個是我們只要找到下個方位就沒有必要在找了 { di++; //當前方塊di = -1的 我們這個保證di依次從0到3可以得到當前方塊的4個方位的方塊 switch (di) { case 0: //注意:由於我們當前的方塊是入棧的,因此我們想要得到當前方塊的上下左右4個方位的話, //直接通過棧裡的資料來得到 當然我們這裡是0方位 表示我們需要得到當前方塊的上一個方塊的座標i和j,後面用來測試是不是可以行走 i = st.data[st.top].i - 1;j = st.data[st.top].j; break; case 1: //得到當前行走方塊的右方塊的座標i和j i = st.data[st.top].i;j = st.data[st.top].j + 1; break; case 2: //得到當前行走方塊的下方塊的座標i和j i = st.data[st.top].i + 1;j = st.data[st.top].j; break; case 3: //得到當前行走方塊的左方塊的座標i和j i = st.data[st.top].i;j = st.data[st.top].j - 1; break; default: break; } if (MG[i][j] == 0) //上面已經得到了i,j,我們這裡就直接判斷對應座標在地圖中是不是可以行走 { //說明當前格子是可以行走的 find = 1; //設定標誌位 }//找到了下個可走的相鄰方塊(i,j) } if (find == 1) //找到了下個可走的相鄰方塊(i,j) { //進行入棧操作 我們是隻要找到可行走方塊就會入棧 st.data[st.top].di = di; //設定當前方塊的方位di值 注意我們的di是上面得到的 //下面是當前方塊可行走的下個方塊的入棧操作 st.top++; //棧指標+1 st.data[st.top].i = i; st.data[st.top].j = j; st.data[st.top].di = -1; //表示下個方位還沒找到 MG[i][j] = -1; //避免重複行走 } else //沒有路徑可以行走 { MG[st.data[st.top].i][st.data[st.top].j] = 0; //讓當前方塊下次可以行走 st.top--; //出棧方塊 } } return false; //表示沒有可走路徑 } int main() { if (!MGPath(1, 1, M, N )) //返回值為false表示沒有找到迷宮路徑 { printf("迷宮沒有路\n"); } return 0; }

測試結果如圖;
這裡寫圖片描述
注意由於我們是用棧儲存的行走方塊,棧是先進後出,所以我們輸出的路徑點是從路徑的終點到起點**