/*
TowerOfHanoi.java 遞迴版 及 模擬呼叫堆疊版 求解河內塔
> java TowerOfHanoi
Hanoi Tower by Implicit Call Stack 遞迴版
A:[3, 2, 1], B:[], C:[] 1: Move disk 1 from A to C
A:[3, 2], B:[], C:[1] 2: Move disk 2 from A to B
A:[3], B:[2], C:[1] 3: Move disk 1 from C to B
A:[3], B:[2, 1], C:[] 4: Move disk 3 from A to C
A:[], B:[2, 1], C:[3] 5: Move disk 1 from B to A
A:[1], B:[2], C:[3] 6: Move disk 2 from B to C
A:[1], B:[], C:[3, 2] 7: Move disk 1 from A to C
A:[], B:[], C:[3, 2, 1]
Hanoi Tower by Explicit Stack 模擬呼叫堆疊版
A:[3, 2, 1], B:[], C:[] 1: Move disk 1 from A to C
A:[3, 2], B:[], C:[1] 2: Move disk 2 from A to B
A:[3], B:[2], C:[1] 3: Move disk 1 from C to B
A:[3], B:[2, 1], C:[] 4: Move disk 3 from A to C
A:[], B:[2, 1], C:[3] 5: Move disk 1 from B to A
A:[1], B:[2], C:[3] 6: Move disk 2 from B to C
A:[1], B:[], C:[3, 2] 7: Move disk 1 from A to C
A:[], B:[], C:[3, 2, 1]
*/
import java.util.Stack;
public class TowerOfHanoi
{
static Stack stackA = new Stack<>(); // 柱A
static Stack stackB = new Stack<>(); // 柱B
static Stack stackC = new Stack<>(); // 柱C
static int nDisks = 5; // Number of disks 盤數
static int count = 0; // 步數
static boolean printGoal = false; // 列印目標否
static boolean printOperation = true; // 列印步驟否
static boolean printStack = false; // 列印模擬呼叫堆疊否
// 印n格空白
public static void printSpaces(int n)
{
for(int i=0; i <= n -1; i++) System.out.print(" ");
}
// 印柱A,柱B,柱C堆疊,前面n層內縮
public static void printStacks(int n)
{
StringBuilder sb = new StringBuilder();
sb.append("A:" + stackA);
sb.append(", B:" + stackB);
sb.append(", C:" + stackC);
System.out.println();
printSpaces(n*8); // 每層內縮8格
System.out.print(sb.toString());
}
// 搬移柱from頂一個盤子到柱to
public static void transfer(char from, char to)
{
if(from=='A' && to=='B') stackB.push(stackA.pop());
if(from=='A' && to=='C') stackC.push(stackA.pop());
if(from=='B' && to=='A') stackA.push(stackB.pop());
if(from=='B' && to=='C') stackC.push(stackB.pop());
if(from=='C' && to=='A') stackA.push(stackC.pop());
if(from=='C' && to=='B') stackB.push(stackC.pop());
}
// 遞迴版解河內塔,將n個盤子從柱sourc,搬到柱target,透過柱auxiliary
public static void solveHanoi(int n, char source, char auxiliary, char target)
{
if(printGoal)
{
System.out.println();
printSpaces((nDisks - n)*8);
System.out.print(String.format("hanoi(n:%d,s:%c -> t:%c)",n,source,target));
}
if (n == 1)
{
if(printOperation)
System.out.print(String.format("\t\t%d: Move disk 1 from %c to %c", ++count, source, target));
transfer(source, target);
}
else
{
solveHanoi(n - 1, source, target, auxiliary);
printStacks(nDisks - n);
if(printOperation)
System.out.print(String.format("\t\t%d: Move disk %d from %c to %c", ++count, n, source, target));
transfer(source, target);
printStacks(nDisks - n);
solveHanoi(n - 1, auxiliary, source, target);
}
}
// 模擬呼叫記錄
static class HanoiCallRecord
{
int num;
char source;
char auxiliary;
char target;
int stage; // 0 for moving n-1 disks from source to auxiliary rods;
// 1 for moving the disk n from source to target rods
// and moving n-1 disks from auxiliary to target rods
// 2 for backtracking to the previous call record
// 建構子
public HanoiCallRecord(int num, char source, char auxiliary, char target)
{
this.num = num;
this.source = source;
this.auxiliary = auxiliary;
this.target = target;
this.stage = 0; // 預設從階段0開始
}
// 列印呼叫記錄
public String toString()
{
return String.format("(n:%d,s:%c,a:%c,t:%c,s:%d)",
num, source, auxiliary, target, stage);
}
}
// 模擬呼叫堆疊,解河內塔,將n個盤子從柱sourc,搬到柱target,透過柱auxiliary
public static void hanoiUsingStacks(int num, char src, char aux, char tgt)
{
Stack stack = new Stack<>();
HanoiCallRecord initial = new HanoiCallRecord(num, src, aux, tgt);
stack.push(initial); // 壓入第1層呼叫記錄
while (stack.isEmpty()==false)
{
if(printStack) System.out.print("\n" + stack);
HanoiCallRecord current = stack.peek(); // 檢視本層呼叫記錄
int n = current.num;
char source = current.source;
char auxiliary = current.auxiliary;
char target = current.target;
int stage = current.stage;
if (n == 1) // 執行特別任務,然後退回上一層任務
{
if(printOperation)
System.out.print(String.format("\t\t%d: Move disk 1 from %c to %c", ++count, source, target));
transfer(source, target);
stack.pop(); // 彈出本層呼叫記錄,
}
else if(stage == 0) // 階段0, 執行本層第0階段任務
{
// solveHanoi(n - 1, source, target, auxiliary);
HanoiCallRecord next = new HanoiCallRecord(n - 1, source, target, auxiliary);
stack.push(next); // 壓入下層呼叫記錄
current.stage++; // 更新本層呼叫記錄的階段欄位
}
else if(stage == 1) // 階段1, 執行本層第1階段任務
{
printStacks(nDisks - n);
if(printOperation)
System.out.print(String.format("\t\t%d: Move disk %d from %c to %c", ++count, n, source, target));
transfer(source, target);
printStacks(nDisks - n);
// solveHanoi(n - 1, auxiliary, source, target);
HanoiCallRecord next = new HanoiCallRecord(n - 1, auxiliary, source, target);
stack.push(next); // 壓入下層呼叫記錄
current.stage++; // 更新本層呼叫記錄的階段欄位
}
else if(current.stage == 2) // 階段2,本層任務完成,退回上一層任務
{
stack.pop(); // 彈出本層呼叫記錄,
}
}
}
// 測試主程式
public static void main(String[] args)
{
nDisks = 3; // Number of disks
count = 0;
for(int i=nDisks; i >= 1; i--) stackA.push(i);
System.out.print("Hanoi Tower by Implicit Call Stack 遞迴版");
printStacks(0);
solveHanoi(nDisks, 'A', 'B', 'C');
printStacks(0);
// ===================================
count = 0;
stackA.clear();
stackB.clear();
stackC.clear();
for(int i=nDisks; i >= 1; i--) stackA.push(i);
System.out.print("\n\nHanoi Tower by Explicit Stack 模擬呼叫堆疊版");
printStacks(0);
hanoiUsingStacks(nDisks, 'A', 'B', 'C');
printStacks(0);
}
}
2023年10月18日 星期三
how to solve the tower of hanoi by recursion versus simulated call stack?
訂閱:
文章 (Atom)