看譚老師著名的C語言教材一直沒有搞懂漢諾塔的遞歸原理,
偶爾看到一本c++教材上講解的比較詳細,就用python寫了一個解法,總共5行代碼,還是挺簡單的。寫的時間比較久遠了,等我找到那本書,再把書中的解析附上。
# 參數的含義爲(盤子總數,起始杆,中間杆,目標杆)
def moveDisk(count, needle1, needle2, needle3):
if count > 0:
# 將除最底盤以外的盤子從1杆移到2杆
moveDisk(count-1, needle1, needle3, needle2)
# 將最底盤從1杆移到3杆
print("move disk", count, "from", needle1, "to", needle3)
# 將除最底盤以外的盤子從2杆移到3杆,任務完成
moveDisk(count-1, needle2, needle1, needle3)
驗證一下結果
#當有三個盤子的時候
moveDisk(3, 'needle1', 'needle2', 'needle3')
輸出結果:
1. move disk 1 from needle1 to needle3
2. move disk 2 from needle1 to needle2
3. move disk 1 from needle3 to needle2
4. move disk 3 from needle1 to needle3
5. move disk 1 from needle2 to needle1
6. move disk 2 from needle2 to needle3
7. move disk 1 from needle1 to needle3
[Finished in 0.2s]
理解的關鍵在於,將3個盤子分成兩部分,即上面的盤子(2個)和底盤(第3個),將上面的2個盤子視爲一個整體,這樣,將3個盤子從1杆移到3杆只需三步:
- 將上面的盤子從1杆移到2杆 (前3步)
- 將底盤從1杆移到3杆 (第4步)
- 將上面的盤子從2杆移到3杆 (後3步)
像不像把大象裝進冰箱這個梗的步驟,只要按遞歸思想實現了代碼,具體的函數如何調用,就交給計算機吧。
當有n個盤子的話,最少需要移動2的n次方減1步。即,3個盤子需要移動2^3-1
終於找到了 ,原書是《C++編程–數據結構與程序設計方法》P339:
關於遞歸思想的理解,可以參考《數據結構與算法分析——C++描述》第三版。
文中c++代碼轉化爲python代碼爲:
def print_out(n):
if n >= 10:
print_out(n // 10) # 先打印7654 (76543//10)
print(n % 10) # 接着打印3 (76543%10)
print_out(76543)
當然,目前看到的對遞歸最詳細易懂的解釋是《C語言程序設計與問題求解(第七版)》第九章,這本書英文名爲《problem solving and program design in c》 ,也被翻譯爲《C語言詳解》