漢諾塔是經典的遞歸算法問題:
移動 n 個盤子從 A 移到 C(借助 B):
import java.util.ArrayList;
import java.util.List;
public class HanoiTowerVisualization {
public static int tiers = 4; // 盤子層數
// 三根柱子,用 List 模擬棧結構(索引 0 為底部)
private static List<String> peg1 = new ArrayList<>();
private static List<String> peg2 = new ArrayList<>();
private static List<String> peg3 = new ArrayList<>();
// 柱子映射,用於打印時確定編號
private static List<String>[] pegs = {peg1, peg2, peg3};
public static void main(String[] args) {
// 1. 初始化:在柱子1上放置盤子
initPeg(peg1, tiers);
System.out.println("=== 初始狀態 ===");
printPegs();
// 2. 執行漢諾塔算法
hanoi(tiers, peg1, peg2, peg3);
System.out.println("\n=== 最終狀態 ===");
printPegs();
}
/**
* 初始化柱子盤子
* 盤子用 "^" 字符表示,寬度為 2*tiers-1,居中對齊
*/
private static void initPeg(List<String> peg, int tiers) {
StringBuilder builder = new StringBuilder();
// 從底層到頂層(i 從 tiers 遞減到 1)
for (int i = tiers; i > 0; i--) {
builder.setLength(0); // 清空
// 左側填充空格:(tiers - i) 個
for (int k = 0; k < tiers - i; k++) builder.append(" ");
// 盤子主體:2*i-1 寬度,奇數位放 "^",偶數位放空格
for (int j = 1; j <= 2 * i - 1; j++) {
builder.append(j % 2 == 1 ? "^" : " ");
}
// 右側填充空格
for (int k = 0; k < tiers - i; k++) builder.append(" ");
peg.add(builder.toString());
}
}
/**
* 打印三根柱子當前狀態
*/
private static void printPegs() {
// 計算最大高度
int maxHeight = Math.max(peg1.size(), Math.max(peg2.size(), peg3.size()));
// 空層佔位符
StringBuilder empty = new StringBuilder();
empty.append("|");
for (int i = 0; i < 2 * tiers - 1; i++) empty.append(" ");
empty.append("|\t");
// 從頂層向下打印(索引 maxHeight-1 到 0)
for (int level = maxHeight - 1; level >= 0; level--) {
for (int p = 0; p < 3; p++) {
List<String> peg = pegs[p];
if (level < peg.size()) {
System.out.print("|" + peg.get(level) + "|\t");
} else {
System.out.print(empty);
}
}
System.out.println();
}
System.out.println();
}
/**
* 漢諾塔遞歸核心方法
* @param n 要移動的盤子數
* @param from 源柱子
* @param aux 輔助柱子
* @param to 目標柱子
*/
public static void hanoi(int n, List<String> from, List<String> aux, List<String> to) {
if (n == 1) {
moveTopDisk(from, to);
return;
}
// 步驟1:將 n-1 個盤子從 from 移到 aux(借助 to)
hanoi(n - 1, from, to, aux);
// 步驟2:將第 n 個盤子從 from 移到 to
moveTopDisk(from, to);
// 步驟3:將 n-1 個盤子從 aux 移到 to(借助 from)
hanoi(n - 1, aux, from, to);
}
/**
* 移動頂部盤子並打印過程
*/
private static void moveTopDisk(List<String> from, List<String> to) {
// 彈出源柱子頂部盤子,壓入目標柱子
String disk = from.remove(from.size() - 1);
to.add(disk);
// 確定柱子編號
int fromNum = 0, toNum = 0;
for (int i = 0; i < pegs.length; i++) {
if (pegs[i] == from) fromNum = i + 1;
if (pegs[i] == to) toNum = i + 1;
}
System.out.println("********** 移動步驟 **********");
System.out.println("從 " + fromNum + " 號柱子 → " + toNum + " 號柱子");
printPegs();
}
}
=== 初始狀態 === | ^ | | | | | | ^ ^ | | | | | | ^ ^ ^ | | | | | | ^ ^ ^ ^ | | | | | ********** 移動步驟 ********** 從 1 號柱子 → 2 號柱子 | | | ^ | | | | ^ ^ | | | | | | ^ ^ ^ | | | | | | ^ ^ ^ ^ | | | | | ...
| 技術點 | 說明 |
|---|---|
| List 模擬棧 | 使用 ArrayList,add/pop 對應壓棧/彈棧 |
| 盤子可視化 | StringBuilder 構建固定寬度字符串,用 "^" 和空格組合 |
| 遞歸終止條件 | n == 1 時直接移動單個盤子 |
| 柱子編號映射 | 通過引用比較 (==) 確定柱子在數組中的索引 |
Thread.sleep(500) 觀察每一步漢諾塔是理解遞歸思想的經典案例。通過可視化輸出,可以直觀看到「大問題分解為子問題」的遞歸過程。代碼結構清晰,分離了算法邏輯與顯示邏輯,便於擴展和教學演示。