棧與遞迴實現迷宮問題求

2021-07-25 09:27:44 字數 4310 閱讀 8010

在學習了資料結構的棧和佇列的相關知識以後,我接觸到了棧的一些應用,其中迷宮問題就是一種棧的應用。

在這個迷宮中我們認為0是可以通過的路徑,而1就相當於牆,是不可以通過的。

基本的實現方法其實是蠻簡單的,我們知道棧的特點就是先進後出,後進先出,所以,當我們從入口開始,將可以通過的路徑的座標壓棧,壓入棧中,但當路徑沒有辦法通過的時候,我們就開始往後面退,這個時候就是路徑座標出棧的過程,每往後退一次,就再一次在這個點上尋找其餘方向是否有可以通過的路徑,沒有就繼續往後面退,有就往新的可以通的方向走,直到走出這個迷宮,這個方法稱之為「回溯法」。

在簡單介紹了大概地實現原理後,我們可以來想一下具體的實現過程了。

由於我們在這裡是通過棧儲存點的座標,所以我們需要乙個能夠表明座標的結構體,結構體中包括這個座標的行和列;接著就是我們在這裡給的迷宮是乙個二維陣列,但是二維陣列我們有時候並不清楚他是需要有多大,而且二維陣列的動態開闢並不方便實現,動態開闢需要去使用陣列指標,顯然這樣是比較麻煩的,在以前c語言學習的時候我們知道二維陣列在記憶體中的儲存方式也還是按照一維陣列的方式,還是一段連續的空間,所以我們還是去使用一維陣列,在細節方面進行一下強轉就好了。

下面我們以**進行分析:

const size_t n = 10;

void getmaze(int *maze,size_t n)

else if (value == eof)

}} fclose(fp);

}void printmaze(int* maze, size_t n)

cout << endl;

} cout << endl;

}struct pos

;//棧的方式(入棧和出棧,將路徑先壓入棧中,然後需要回溯的時候將壓入棧的路徑再出棧)

bool getmazepath(int* maze, size_t n, pos entry, stack& path)

next = cur;

//上next.row -= 1;

if (maze[next.row * n + next.col] == 0)

next = cur;

//下next.row += 1;

if (maze[next.row * n + next.col] == 0)

next = cur;

//左next.col -= 1;

if (maze[next.row * n + next.col] == 0)

next = cur;

//右next.col += 1;

if (maze[next.row * n + next.col] == 0)

next = cur;

path.pop();

} return false;

}

在這個**中getmaze()就是獲取迷宮的函式,其中用檔案進行讀取,讀到錯誤會丟擲異常。printmaze()就是列印函式了。

最主要的是下面的getmazepath()函式了,這是為了獲取路徑的。在這個函式中,我們可以進行一下分析:

首先是傳參部分,引數首先得把這個迷宮,也就是這個陣列得傳進去,然後,要想進入這個迷宮,那麼你得需要乙個入口吧,當然,最後你還需要乙個棧,也就是儲存的路徑。

然後我們在這裡需要看的就是具體的實現方法了,你從迷宮入口進入,每走過乙個點,你需要將這個點做一下標記,總不能啥都不做吧,要不然豈不是相當於沒走過咯。當然,你還得知道自己到底有沒有走出這個迷宮對吧,那麼你就需要乙個判斷出迷宮的條件,這個也是比較簡單,只要出了這個迷宮的範圍,那不就出去了麼。做好了這一部分,那麼我們需要考慮的就是如何具體的去走這個迷宮了。之前我說過,走過的迷宮的路徑是進行壓棧的,那麼只要棧不為空,就表示我還在迷宮裡面走,如果棧空了,就說明你已經回退出去了,那麼就說明迷宮沒有出口。

假設你現在在迷宮裡面走,只要遇到不是1的牆,是0的路,那麼你就走,當你遇到岔路口時,你可以隨意先挑乙個方向去走,如果走不通你就回退,退到你可以往沒走過的地方走時向新的方向走。

下面我給**新增注釋,希望可以方便你去理解。

bool getmazepath(int* maze, size_t n, pos entry, stack& path)

next = cur;//先將當前座標進行拷貝

//上next.row -= 1;//在這裡將行退一步,表示你現在在往上走,然後next就成為下乙個點了

if (maze[next.row * n + next.col] == 0)//判斷往上走是否可以通過,可以就進入,不可以就繼續這個迴圈

next = cur;

//下面的與上面的基本一致,只是方向略有不同
//下

next.row += 1;

if (maze[next.row * n + next.col] == 0)

next = cur;

//左next.col -= 1;

if (maze[next.row * n + next.col] == 0)

next = cur;

//右next.col += 1;

if (maze[next.row * n + next.col] == 0)

next = cur;

path.pop();//如果4個方向都沒有進去,說明四個方向都不通了,那麼此刻只能往回倒退,讓這個點出棧,退回上乙個點

} return false;

}

下面就是我的測試**,我把結果也一同顯示:

void testmaze()

; maze[entry.row ][ entry.col] = 2;

stackpath;

stackshortpath;

getmazepath((int*)maze, n, entry, path);

cout << "是否找到迷宮出口" << !path.empty() << endl;

printmaze((int*)maze, n);

}

最終輸出的結果顯示是:

上面我講了使用棧的方法,接著我就介紹一下遞迴的方法。

大家都知道,遞迴在某種程度上就可以當做是迴圈進行使用,那麼我們只需要改一點點地方,就可以實現遞迴的方法了。

你可以仔細思考一下,我把**先給你看

void getmazepath_r(int* maze, size_t n, pos entry, stack& path)

next = cur;

//上next.row -= 1;

if (maze[next.row * n + next.col] == 0)

next = cur;

//下next.row += 1;

if (maze[next.row * n + next.col] == 0)

next = cur;

//左next.col -= 1;

if (maze[next.row * n + next.col] == 0)

next = cur;

//右next.col += 1;

if (maze[next.row * n + next.col] == 0)

}

看完這個**你看懂了沒,其實方法很簡單,你只需要

將下乙個你將走的點當做路口點再去呼叫就好了,每一次的呼叫都將會讓你往後走,你只需要用棧儲存一下這個點的座標就好了。只要想通了其實是很簡單的。

下面我把測試函式和結果顯示一下:

void testmaze()

; maze[entry.row ][ entry.col] = 2;

stackpath;

stackshortpath;

getmazepath_r((int*)maze, n, entry, path);

cout << "是否找到迷宮出口" << !path.empty() << endl;

在這個結果裡面你會發現遞迴的乙個壞處就是他會將所有可以走過的點都去遍歷一遍。即便你已經走出了這個迷宮,它還是會將可以走的點都走一遍的。

注:**是放在vs2013下進行編譯執行的。

棧和遞迴 解決迷宮問題

走過的路設定為2,未走過的路設定0,牆設定為1 如下 bool checkpath const pos cur bool getmazepath pos entry pos next cur 上next.row 1 if checkpath next next cur 右next.col 1 if ...

非遞迴迷宮問題實現

模組化,重整程式 class lstack def init self,top 1,full 20 self.top top self.stack self.full full def is full self return self.full self.top 1 def is empty sel...

棧實現迷宮求解問題

總體感觸是 不要著急,一步一步來,問題很容易解決的。首先是要實現乙個迷宮的地圖。明確如何儲存地圖,用vector實現二維陣列,每個元素代表地圖的乙個格仔。需要儲存哪些資訊。一張地圖的某乙個方格需要標示 能否通過,是否走過了。94 struct point 位置資訊可用postype儲存。就是 str...