有關問題的遞迴實現和非遞迴實現其實是我們理解計算機,或者說程式語言中關於函式呼叫的方式最好的方式之一,它讓我們知道了某種程式語言在實現函式呼叫的方式,也是計算機程序切換的一種思想的體現。
我們先來說說漢諾塔問題:
漢諾塔問題是乙個經典的問題。我們先來看看漢諾塔問題的遞迴解決思路:漢諾塔(hanoi tower),又稱河內塔,源於印度乙個古老傳說。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64片**圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,任何時候,在小圓盤上都不能放大圓盤,且在三根柱子之間一次只能移動乙個圓盤。問應該如何操作?
將 a 上的 n-1 個盤子通過以 c 為輔助移動到 b
將 a 上剩餘的最大的盤子直接移動到 c
將 b 上的 n-1 個盤子通過 a 為輔助移動到 c
這其實是我們說過無數次的遞迴思路,**實現很簡單:
// 遞迴實現漢諾塔
// n 為漢諾塔圓盤編號,從小到大為 1,2,3,……
void
hanoi
(int n,
char a,
char b,
char c)
else
}
遞迴時候的思路很清晰明了,我們可以通過 debug 看到函式棧的呼叫,每個函式幀儲存了當前函式所需要的引數,當函式棧頂層的函式都執行完畢時,這個函式被彈出pop,然後根據所儲存的資訊來執行。
而非遞迴實現,其實也就是需要我們手動模擬出函式棧,需要用函式棧儲存一些引數。
我們可以定乙個結構體status
來儲存當前狀態的引數,隨後當 pop 到這個函式時就可以直接讀取使用。
不光是漢諾塔的非遞迴實現,包括我們的 bfs 的實現,其實也是使用棧來儲存當前的狀態資訊,我們都可以使用乙個status
來儲存。
// 儲存函式狀態
struct status
};
而棧的使用又有乙個特點,那就是 filo,也就是先進後出,所以我們需要按照遞迴函式呼叫的反向來儲存狀態,也就是先呼叫的後 push 到棧中。
從而我們得到了非遞迴的實現。
// 採用非遞迴實現漢諾塔問題
// 由於棧的特殊性質,filo,所以我們需要將原來函式的呼叫方式反過來進行
void
hanoistack
(int n,
char a,
char b,
char c)
else
}}
我們通過非遞迴解決方式得到了一種遞迴問題的另外一種解決方法,在我們手動去寫遞迴函式的時候,其實是作業系統或者說程式語言幫助我們實現了函式棧,幫助我們儲存了每次使用所需要的引數。
而且在很多時候,非遞迴的實現方式可以幫助我們節省系統資源,幫助我們節約寶貴的系統資源。
漢諾塔的遞迴和非遞迴實現
漢諾塔的遞迴和非遞迴實現 借助堆疊以非遞迴 迴圈 方式求解漢諾塔的問題 n,a,b,c 即將n個盤子從起始柱 標記為 a 通過借助柱 標記為 b 移動到目標柱 標記為 c 並保證每個移動符合漢諾塔問題的要求。輸入為乙個正整數n,即起始柱上的盤數。每個操作 移動 佔一行,按柱1 柱2的格式輸出。3a ...
pta 漢諾塔的非遞迴實現
借助堆疊以非遞迴 迴圈 方式求解漢諾塔的問題 n,a,b,c 即將n個盤子從起始柱 標記為 a 通過借助柱 標記為 b 移動到目標柱 標記為 c 並保證每個移動符合漢諾塔問題的要求。輸入格式 輸入為乙個正整數n,即起始柱上的盤數。輸出格式 每個操作 移動 佔一行,按柱1 柱2的格式輸出。輸入樣例 3...
3 2 漢諾塔的非遞迴實現
漢諾塔實現的基本思路是 不斷將n個盤的漢諾塔問題轉換為2個 n 1 個盤的漢諾塔問題,用遞迴實現比較好理解。設n盤問題為 n,a,b,c 其中引數如下結構體所定義,第乙個引數表示需要移動的盤子的數量,第二個引數表示n個盤子起始所在柱子a,第三個引數表示會被借用的柱子b,第四個引數表示這 n個盤子所在...