資料結構之棧的應用 迷宮求解

2021-06-06 19:05:46 字數 3278 閱讀 8677

/***********程式設計思想*************/

(1)迷宮地圖相關:

利用動態二維陣列來初步勾勒出迷宮:

建議先用malloc申請一維陣列,再用calloc申請每個元素中的一維陣列,因為我用的是1來表示迷宮的通路,0表示死路,calloc申請完後就會自動初始化為0

迷宮交岔路結點:

我們要有乙個掃瞄通路的函式,對乙個座標進行東南西北的掃瞄,當遇到交岔路的座標時,需要將所有的通路存入乙個陣列,掃瞄從東開始,至北結束,逆時針方向

這裡設計的是單通道迷宮,也就是說不會有並行的通路,掃瞄出來的通路是不會超過兩個的(肯定是不允許把結點來的那個原始方向認為是通路的)

當我們按著第乙個方向走到死路時,我們需要返回到最近的乙個交岔路結點,這之後第乙個最重要的操作便是:將已確定的死路給封死,即把那個座標的值從1改為0。

(2)棧相關:

棧在這裡需要兩個,乙個存放走過的路徑,也就是移動到乙個座標,就把這個座標入棧,另乙個是存放交岔路結點的,當我們遇到死路之後,就需要從交岔路結點棧中

彈出乙個元素a,然後從所有路徑的棧中一直彈出元素(就是原路返回),直到棧頂元素b與a相等,就表明已經退回到了最近的乙個交岔路口

下一步便是走向另乙個通路,直到遇到死路或終點

(3)設計根本:

整個程式是建立在遞迴應用中的,抽象出來就是:當我們規定乙個優先方向(預設為東方向吧)、再規定乙個固定的旋轉方向(預設為逆時針)之後,我們會有乙個從東方、

沿逆時針、到北方的總體走向,遇到乙個死胡同,我們就要沿著路徑原路返回,直到遇到乙個十字路口,再走向另乙個可通的方向,要是還是死胡同,就返回到再前乙個十字

路口,進入另乙個可通的方向,如此反覆的探索,知道走到終點。

/***********程式設計細節*************/

(1)掃瞄通道函式----int scan_direction(data_type elem,int *all_direction,int **labyrinth);

返回值:返回所有可通方向的數量,可能值為0,1,2

重要引數:all_direction:記錄所有可通的方向

關鍵實現:

if(labyrinth[elem.x][elem.y+1] == yes && elem.direction != east)

座標是按照二維陣列的行列來規定的,這裡給出的是判斷當前座標的東向是可通,yes表明可通,當座標的東鄰座標([elem.x][elem.y+1])值為yes的時候,我們並不能

elem.direction != east,只有當這兩個條件同時滿足的時候才表明東鄰為通,其餘三個方向的判斷與之類似

(2)根據方向的數目來走迷宮

case 1:先看只有乙個方向可走到時候

這種情況很好解決,按著掃瞄的方向走一步就ok,讓移動後的座標入棧即可,這裡我遇到了乙個小問題,就是由於很多次的往回走,每一次都要入棧或出棧,貌似這樣可能

造成路徑棧中存在幾個相同的座標,並且這些座標在棧中都是相鄰的,所以我在每次入棧的時候都判斷了一下,如果和棧頂元素相同,就不入棧了,以免最後彈出正確路徑的

時候出現多個重複的座標

case 2:這個條件是程式的關鍵部分,總的來說就是先走乙個方向,若未遇到終點,就返回到交岔路結點,再走向另一條路,反覆直到走到終點

case 2:

break;

首先讓交岔路結點入棧(交叉點棧),讓這個點入路徑棧

接下來就是走向第乙個方向,進入這個方向後,position將先通過all_direction[0]方向移動一格,然後利用遞迴,對新座標進行掃瞄,判斷出可通方向個數(0,1,2三種),

接著就開始重複昨天的故事,也就是遞迴了,當這乙個方向走完後,這個move_path就結束了,然後判斷是否到了終點,如果不是終點就進入第二個move_path,繼續遞迴,

知道走到終點

這種遞迴過程,完全可以利用二叉樹的圖形來理解,先走完乙個方向,再走另乙個方向,二叉樹如圖:

箭頭代表單通道,x代表死路

路線;起點-->1-->3-->(彈出3)1-->4-->(彈出4、1)-->起點....

這是左方向的走法,右方向按著這個方法走下去就能找到終點。

case 0:

當我們到了交叉點3的時候,會發現它是乙個死胡同,即可通方向為0,這個時候就需要不斷的彈出路徑棧的元素,一直到交叉點1,進入交叉點4的方向。

(3)封掉已經確定的死路

當我們彈出交叉點1,返回到起點時,我們就可以確定從交叉點1走到方向的所有路都不可能走到終點,這個時候,我們就可以封掉交叉點1,即

把此座標的值從1變為0

其實進行第二次move_path的時候,座標已經到了交叉點2了,也就是說在交叉點2處掃瞄的時候,是不會檢測交叉點1的,這樣看來封掉死路似乎

沒有必要,確實是的,但是如果你設計的move_path沒有一進入就將座標移到下乙個位置的話,這個東西就必要了,也就是你再次在起點掃瞄可能

會又把交叉點1掃瞄進去,就造成了乙個無限的函式巢狀了。。。

封掉死路只是乙個我們思考的乙個常識,根據個人而定。

(4)走迷宮迴圈的第一步(關鍵):

if(count_direction != 0)

else

這個**應該算得上短小精悍,if條件語句表示在上一次迴圈中不是在case 0的switch語句中結束的,因為case 0本身就表示掃瞄的方向為0,如果這裡沒有這個判斷,

那麼滿足下面兩個條件的時候,程式就會出現問題:

1、上一次迴圈就是在case 0中結束的;

2、上一次迴圈存在於case 2中的第乙個move_path中,而本次迴圈剛好又要求進入第二個move_path

即是:起始座標是乙個交叉點,all_direction本身就已經儲存了兩個方向,當你按第乙個方向走到死路(case 0),你的position重新返回到了交叉點,這個時候你本該

退出這個函式,用all_direction中的第二個方向走下去,但是你卻不可能退出while迴圈,因為你的position依舊要進行掃瞄,並且結果同樣進入case 0,這樣就會陷入死

迴圈,我們就需要加上這個if-else語句,當count_direction等於0時,就表明是從case 0中來的,就應該break,進入第二個函式

《資料結構》 棧的應用 迷宮求解問題

利用棧求解迷宮問題 只輸出乙個解,演算法3.3 typedef struct 迷宮座標位置型別 postype define maxlength 25 設迷宮的最大行列為25 typedef int mazetype maxlength maxlength 迷宮陣列 行 列 全域性變數 mazety...

資料結構 迷宮求解

定義迷宮 include seqstack.h define max row 6 最大行數 define max col 6 最大列數 typedef struct mazemaze void mazeinit maze maze size t i 0 for imap i j map i j vo...

資料結構 迷宮求解

include include int mg 10 10 地圖 int m 8 行數 int n 8 列數 typedef struct box 定義方塊型別 typedef struct sttype 定義順序棧型別 bool mgpath int xi,int yi,int xe,int ye ...