前言
汉诺塔(Tower of Hanoi) 是一个经典的数学问题和递归算法案例,最早由法国数学家爱德华·卢卡斯(Édouard Lucas)于1883年提出。这个问题不仅具有理论意义,还被广泛用于编程和算法教学中。
提示:以下是本篇文章正文内容,下面案例可供参考
一、问题描述
- 场景:有三根柱子(通常标记为A、B、C),其中一根柱子(如A)上叠放若干大小不同的圆盘,从上到下按从小到大的顺序排列。
- 目标:将所有圆盘从起始柱子(如A)移动到目标柱子(如C),过程中可以借助中间柱子(如B)。
- 规则:
-
每次只能移动一个圆盘。
-
任何时候,较大的圆盘不能放在较小的圆盘上方。
-
只能移动柱子最顶端的圆盘。
-
二、解决思路(递归方法)
汉诺塔问题的经典解法基于递归思想。对于 n 个圆盘的问题,可以分解为以下步骤:
-
将前 n-1 个圆盘从起始柱移动到中间柱(借助目标柱)。
-
将第 n 个(最大的)圆盘从起始柱直接移动到目标柱。
-
将 n-1 个圆盘从中间柱移动到目标柱(借助起始柱)。
递归终止条件:当只剩一个圆盘时,直接将其移动到目标柱。
三、示例
示例(3个圆盘)
假设柱子为A(起始柱)、B(中间柱)、C(目标柱):
-
移动圆盘1:A → C
-
移动圆盘2:A → B
-
移动圆盘1:C → B
-
移动圆盘3:A → C
-
移动圆盘1:B → A
-
移动圆盘2:B → C
-
移动圆盘1:A → C
图解:
综上:总的就是和解决思路一样,先将第一个盘子上面两个盘子通过第三个盘子全部移动到第二个盘子中,然后再将第一个盘子最后的一个盘子直接移动到第三个盘子中,最后第二个盘子中所有的盘子,通过第一个盘子移动到最后一个盘子。
四、时间复杂度
时间复杂度
-
移动 n 个圆盘需要的最少步骤数为 2ⁿ - 1(指数级复杂度)。
-
时间复杂度为 O(2ⁿ),因此当圆盘数量较大时,计算量会急剧增加。
五、代码实现
//汉诺塔问题
public static void move(char pos1,char pos2) {
System.out.print(pos1+"->"+pos2+" ");
}
public static void hanoi(int n,char pos1,char pos2,char pos3) {
if(n == 1) {
move(pos1,pos3);
return;
}
hanoi(n-1,pos1,pos3,pos2);
move(pos1,pos3);
hanoi(n-1,pos2,pos1,pos3);
}
public static void main(String[] args) {
hanoi(3,'a','b','c');
}
代码理解
注意这里函数里面加了return语句是为了让他返回给上一个调用,不然该函数就会一直递归下去没有回归。
理解需要参考示例及解决思路进行理解
- pos1,pos2,pos3
首先三个pos代表三个位置,分别是示例中的a、b、c三个盘子,a代表首位置,b代表中转位置,c代表末位置。而游戏的规则也很简单,就是通过中转位置b将a的盘子移动到c中。
- 如果只有一个盘子,就是直接从a首位置移动到末位置,这是递归结束条件。
move(pos1,pos3);
- 如果超过一个盘子的话,我们就得先将首位置中最后一个盘子前面的盘子,通过c全部移动到b,所以此时的话c就是中转位置。
hanoi(n-1,pos1,pos3,pos2);
- 根据示例中下一步我们就是将首位置中唯一一个盘子移动到最终位置。
move(pos1,pos3);
- 最后我们需要将中间位置b的盘子通过a位置,全部移动到c位置中。此时b就是首位置,a就是中转位置,c就是末位置
hanoi(n-1,pos2,pos1,pos3);