漢諾塔問題是一個經典的問題。漢諾塔(Hanoi Tower),又稱河內塔,源於印度一個古老傳說。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞着64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,任何時候,在小圓盤上都不能放大圓盤,且在三根柱子之間一次只能移動一個圓盤。問應該如何操作?
分析
假設除最下面的盤子之外,我們已經成功地將上面的63個盤子移到了b柱,此時只要將最下面的盤子由a移動到c即可。如圖:
當最大的盤子由a移到c後,b上是餘下的63個盤子,a爲空。因此現在的目標就變成了將這63個盤子由b移到c。這個問題和原來的問題完全一樣,只是由a柱換爲了b柱,規模由64變爲了63。因此可以採用相同的方法,先將上面的62個盤子由b移到a,再將最下面的盤子移到c……對照下面的過程,試着是否能找到規律:
- 將b柱子作爲輔助,把a上的63個圓盤移動到b上
- 將a上最後一個圓盤移動到c
- 將a作爲輔助,把b上的62個圓盤移動到a上
- 將b上的最後一個圓盤移動到c
- ......
也許你已經發現規律了,即每次都是先將其他圓盤移動到輔助柱子上,並將最底下的圓盤移到c柱子上,然後再把原先的柱子作爲輔助柱子,並重復此過程。
這個過程稱爲遞歸,即定義一組基本操作,這組操作將規模小一點(或大一點)的操作當做一個整體——無需關心它的細節,只當它已經完成了——然後執行剩下的操作。而在更小或更大的規模中也依此操作,直到規模達到預定值。
我們假設函數func(n, a, b, c)用於將n個圓盤由a移動到c,b作爲輔助柱子。那麼我們可以這樣實現這個遞歸過程:
func: if n!=0 then ;預定值 func(n-1, a, c, b) ;將n-1個盤子由a移動到b,以c爲輔助柱子(注意參數順序) move a[n] to c ;將a上的最後一個盤子移動到c func(n-1, b, a, c) ;將n-1個盤子由b移動到c,以a爲輔助柱子 endif ;完成
func中有兩個遞歸調用,它們的規模剛好比n小1。註釋說明了每行代碼的作用和意圖。正如註釋裏所強調的那樣,注意參數的順序——參數位置不同,其代表的意義也不一樣