利用棧資料結構徹底搞定走迷宮案例解析(並非最短路徑)
**先上迷宮圖
迷宮資料圖我們分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;
}
測試結果如圖;
注意由於我們是用棧儲存的行走方塊,棧是先進後出,所以我們輸出的路徑點是從路徑的終點到起點**