汉诺塔递归解法的核心是结构化拆解而非效率优化,其本质是将n盘移动分解为三步:移n-1盘、移最大盘、再移n-1盘,终止条件为n=1,参数角色随递归动态流转。

用递归解决汉诺塔问题,核心不在“高效”二字,而在于准确、清晰、可复现地表达问题本质。它本身时间复杂度是 $ O(2^n) $,无法真正“提速”,但递归写法让逻辑零冗余、无歧义,这才是工程和教学意义上的“高效”。
递归解法的关键逻辑
汉诺塔不是靠技巧拼凑步骤,而是靠结构化拆解:
- 把移动 $ n $ 个盘子的问题,严格分解为三个动作:
1. 把上面 $ n-1 $ 个盘子从起始柱(A)移到中转柱(B),借助目标柱(C);
2. 把最底下那个最大盘子直接从 A 移到 C;
3. 再把那 $ n-1 $ 个盘子从 B 移到 C,借助 A。
这三步里,第1步和第3步形式完全相同,只是参数位置轮换——这正是递归成立的充要条件。
终止条件必须明确且唯一
- 当 $ n = 1 $ 时,不再拆分,直接
move(A, C)。 - 这是整个递归链条的“锚点”。缺了它,函数会无限调用下去;写错位置(比如写成
n == 0才返回),会导致少一步移动或空操作。
参数角色要动态理解,不能死记硬背
函数签名通常是:
立即学习“Java免费学习笔记(深入)”;
void hanoi(int n, char from, char aux, char to)
-
from是当前这批盘子的出发柱; -
to是它们的最终目的地; -
aux是临时借用来存放中间状态的柱子。
每次递归调用时,这三个角色都会根据上下文重新分配:
- 第一次递归:
hanoi(n-1, from, to, aux)→ 把 $ n-1 $ 个盘子暂存到aux; - 第二次递归:
hanoi(n-1, aux, from, to)→ 把它们从aux搬到to。
记住:不是“A→B→C”固定流程,而是“源→辅→目标”的角色流转。
实际代码只需四行,但每行都有语义重量
public static void hanoi(int n, char from, char aux, char to) {
if (n == 1) {
System.out.println(from + "->" + to);
return;
}
hanoi(n - 1, from, to, aux); // 上面n-1个先腾到辅助位
System.out.println(from + "->" + to); // 最大盘一步到位
hanoi(n - 1, aux, from, to); // 把n-1个从辅助位搬进目标位
}- 第1行判断终止;
- 第2行输出原子操作(不可再分);
- 第3、4行是递归主体,严格对应前述三步中的第1步和第3步;
- 中间那句
from->to就是整个问题里唯一不可跳过的物理移动,其余全是调度。
不复杂但容易忽略


















