生活随笔
收集整理的這篇文章主要介紹了
汉诺塔递归与非递归实现
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
漢諾塔遞歸與非遞歸實現(xiàn)
背景介紹
漢諾塔(Tower of Hanoi),又稱河內(nèi)塔,是一個源于印度古老傳說的益智玩具。大梵天創(chuàng)造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。并且規(guī)定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。
一、漢諾塔的遞歸實現(xiàn):
對于漢諾塔的遞歸實現(xiàn),我們來這樣理解:
無論如何我們都需要將第n個盤子移動到C柱子上。 我們什么時候能夠取到第n個盤子,必須要把1~n-1個盤子取下來。 當(dāng)我們把第n個盤子放到C柱子上后,這時候不就變成了n-1個盤子的漢諾塔了嗎?因為無論無何都不會再移動比n大或者相同的盤子號,所以我們只需要將1~n-1個盤子從B柱子移動到C柱子上。 如果沒有盤子,我們就不需要做任何操作。 當(dāng)我們需要實現(xiàn)n個盤子的操作,就表示我們必須要實現(xiàn)n-1個盤子的操作;當(dāng)我們需要實現(xiàn)n-1個盤子的操作,就表示我們必須要實現(xiàn)n-2個盤子的操作…
綜上所述,我們來想象一個函數(shù),它能夠完成n個盤子的漢諾塔。這樣子的話我們也可以借助這個想象的函數(shù)來實現(xiàn)n-1個盤子的漢諾塔。那么這個函數(shù)的結(jié)構(gòu)我們很容易想到:
//表示將n個盤子的漢諾塔從origin開始經(jīng)過pass到達(dá)destination的偽代碼:
void func(n, origin, pass, destination){if(n == 0){ return; } // 終止條件。func(n-1, origin, destination, pass); // 首先將n-1個盤子借助C柱移動到B柱上。move(n, origin, destination) // 移動第n個盤子。func(n-1, pass, origin, destination); // 最后將n-1個盤子借助B柱移動到C柱上。return;
}
代碼如下:
# 源代碼
#include <cstdio>
#include <stack>
#include <cmath> using namespace std
; void reHanoi ( int , char , char , char ) ; int main ( ) { int n
; printf ( "please input the number of Hanoi: " ) ; scanf ( "%d" , & n
) ; reHanoi ( n
, 'A' , 'B' , 'C' ) ; return 0 ;
} void reHanoi ( int n
, char from
, char pass
, char to
) { if ( n
== 0 ) { return ; } reHanoi ( n
- 1 , from
, to
, pass
) ; printf ( "%d: %c-->%c\n" , n
, from
, to
) ; reHanoi ( n
- 1 , pass
, from
, to
) ; return ;
}
二、漢諾塔的非遞歸實現(xiàn):
1.借助棧實現(xiàn)漢諾塔的非遞歸形式: 在reHanoi(n-1, from, to, pass)進(jìn)入遞歸前,我們需要保留調(diào)用現(xiàn)場,將參數(shù)入棧,使用新的參數(shù)調(diào)用reHanoi函數(shù)。在此過程中需要一直進(jìn)行入棧操作,直到參數(shù)n ==0為止。對此行為,我們可以用一個循環(huán)來模擬。在eHanoi(n-1, pass, from, to)函數(shù)前,我們要完成當(dāng)前最后一個盤子的移動操作,再產(chǎn)生新的參數(shù),跳轉(zhuǎn)到func語句執(zhí)行;
//偽代碼:
func: while (n > 0 || !stack.empty())int i = n;while (i != 0) {push(i);i --;}int curNum= pop();if(curNum == 0){continue;}printfElem(curNum);n = curNum;n --; push(n);}
# 源代碼
#include <cstdio>
#include <stack>
#include <cmath> using namespace std
; typedef struct elemHanoi
{ int num
; char from
; char pass
; char to
;
} elemHanoi
; void oneNotReHan ( elemHanoi
) ;
elemHanoi
getElem ( int n
, char from
, char pass
, char to
) ;
void printElem ( elemHanoi elem
) ; int main ( ) { int n
; printf ( "please input the number of Hanoi: " ) ; scanf ( "%d" , & n
) ; elemHanoi elem
= { n
, 'a' , 'b' , 'c' } ; oneNotReHan ( elem
) ; return 0 ;
} elemHanoi
getElem ( int n
, char from
, char pass
, char to
) { elemHanoi elem
= { n
, from
, pass
, to
} ; return elem
;
} void printElem ( elemHanoi elem
) { printf ( "%d from %c throught %c to %c\n" , elem
. num
, elem
. from
, elem
. pass
, elem
. to
) ; return ;
} void oneNotReHan ( elemHanoi elem
) { elemHanoi tempElem
= elem
; int number
; stack
< elemHanoi
> myStack
; myStack
. push ( elem
) ; while ( tempElem
. num
> 0 || ! myStack
. empty ( ) ) { while ( tempElem
. num
> 0 ) { tempElem
= getElem ( tempElem
. num
- 1 , tempElem
. from
, tempElem
. to
, tempElem
. pass
) ; myStack
. push ( tempElem
) ; } if ( ! myStack
. empty ( ) ) { tempElem
= myStack
. top ( ) ; myStack
. pop ( ) ; if ( tempElem
. num
== 0 ) { continue ; } printf ( "%d: %c-->%c\n" , tempElem
. num
, tempElem
. from
, tempElem
. to
) ; tempElem
= getElem ( tempElem
. num
- 1 , tempElem
. pass
, tempElem
. from
, tempElem
. to
) ; myStack
. push ( tempElem
) ; } } return ;
}
2.借鑒滿二叉樹實現(xiàn)漢諾塔的非遞歸形式: 對于漢諾塔的步驟,我們其實可以看作對一個滿二叉樹的中序遍歷,從上往下分別為第1層(4號盤),第2層(3號盤),第3層(2號盤),第4層(1號盤)。關(guān)于本方法的詳細(xì)介紹請參看文獻(xiàn),鏈接在文章末尾。 在n=4時我們其實可以明顯的看出,第4層(即最下層)滿足AB 、BC、CA的循環(huán)。 總而言之,奇數(shù)層的移動規(guī)律為AC、CB、BA , 而偶數(shù)層的移動規(guī)律為AB 、BC、CA的循環(huán)。
#include <cstdio>
#include <stack>
#include <cmath> using namespace std
; void twoNotReHan ( int n
) ; int main ( ) { int n
; printf ( "please input the number of Hanoi: " ) ; scanf ( "%d" , & n
) ; twoNotReHan ( n
) ; return 0 ;
}
void twoNotReHan ( int n
) { if ( n
< 1 ) { return ; } int sum
= pow ( 2 , n
) ; int index
= 1 ; while ( index
< sum
) { int floor
= 1 ; int number
= index
; while ( number
% 2 == 0 ) { floor
+ = 1 ; number
/ = 2 ; } if ( ( n
- floor
+ 1 ) % 2 == 1 ) { switch ( number
% 3 ) { case 0 : printf ( "%d: C-->B\n" , floor
) ; break ; case 1 : printf ( "%d: A-->C\n" , floor
) ; break ; case 2 : printf ( "%d: B-->A\n" , floor
) ; break ; } } else { switch ( number
% 3 ) { case 0 : printf ( "%d: B-->C\n" , floor
) ; break ; case 1 : printf ( "%d: A-->B\n" , floor
) ; break ; case 2 : printf ( "%d: C-->B\n" , floor
) ; break ; } } index
++ ; } return ;
}
1、參考文章:漢諾塔問題的非遞歸實現(xiàn) 2、參考文獻(xiàn):譚羅生,吳福英,黃明和. Hanoi塔問題的解模型[J]. 計算機(jī)應(yīng)用與軟件,2004,21(10):49-51.
總結(jié)
以上是生活随笔 為你收集整理的汉诺塔递归与非递归实现 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。