//================================================= // File Name : Tower_demo //------------------------------------------------------------------------------ // Author : Common //主類 //Function : Tower_demo public class Tower_demo { static int nDisks = 3; public static void main(String[] args) { // TODO 自動生成的方法存根 doTower(nDisks, 'A', 'B', 'C'); } public static void doTower(int topN,char from,char inter,char to){ if(topN == 1) System.out.println("Disk 1 from "+from+" to "+to); else{ doTower(topN-1, from, to, inter); System.out.println("Disk "+topN+" from "+from+" to "+to); doTower(topN-1, inter, from, to); } } }
通過二叉樹的中序遍歷過程來分析漢諾塔問題:
考慮A、B、C三根柱子,A上從上到下有1、2、3三個數,要把A上的數移動到C上,其過程應該是
A B C
初始 123
A->C 23 1
A->B 3 2 1
C->B 3 12
A->C 12 3
B->A 1 2 3
B->C 1 23
A->C 123
可以寫成下圖二叉樹的中序遍歷
在程序中有兩個輸出語句,
結束條件中的數據語句輸出的是二叉樹中的葉子結點
遞歸左子樹和遞歸右子樹中間的輸出語句輸出是所有的非葉子結點
所有左孩子和右孩子輸出語句中得到的實際參數都是其父結點傳遞的,根節點輸出語句得到的參數是初始傳遞的參數
<1>首先確定遞歸函數的形式
doTower(int topN,char from,char inter,char to)
<2>在main中給根節點傳遞的初始值為(A,B,C)
對於根節點的輸出A->C
可以確定遞歸左子樹和遞歸右子樹中間的輸出語句應該輸出 from->to,即
System.out.println("Disk "+topN+" from "+from+" to "+to);
<3>步驟<2>確定了遞歸左子樹和遞歸右子樹中間的輸出語句的格式,
對於根節點(A->C)的左孩子(A->B)和右孩子(B->C),由於都是非葉子結點,所以它們使用的仍然是遞歸左子樹和遞歸右子樹中間的輸出語句 from->to,
所以對於左孩子(A->B),要輸出(A->B),可以確定出給其傳遞的參數應該是(A,C,B)
對於右孩子(B->C),要輸出(B->C),可以確定出給其傳遞的參數應該是(B,A,C)
又因為所有左孩子和右孩子輸出語句中得到的實際參數都是其父結點傳遞的,由於父節點得到的實參是(frmo=A,inter=B,to=C)
左孩子要想得到(A,C,B),給其傳遞的順序應該是(from,to,inter)
右孩子要想得到(B,A,C),給其傳遞的順序應該是(inter,from,to)
即確定了
doTower(topN-1, from, to, inter); doTower(topN-1, inter, from, to);
<4>最后確定結束條件中的輸出語句的輸出順序
由於上一步確定了
doTower(topN-1, from, to, inter); doTower(topN-1, inter, from, to);
對於A->B的左孩子A->C,由於在A->B結點中,from=A,inter=C,to=B,所以執行了doTower(topN-1, from, to, inter)后,給A->C傳遞的參數應該是(A,B,C),想要輸出A->C,可以確定結束條件中的輸出語句為
System.out.println("Disk 1 from "+from+" to "+to);
同理,對於A->B的右孩子C->B,由於在A->B結點中,from=A,inter=C,to=B,所以執行了doTower(topN-1, inter, from, to)后,給C->B傳遞的參數應該是(C,A,B),可以輸出C->B