引言
汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从上面开始按大小顺序重新摆放在另一根柱子上。
1. 玩游戏
为了大家能更好的理解代码,建议去玩一下游戏,(电脑端)点这即可
那么,话不多说,我们一起来看看吧!
2. 题目描述
有三根柱子,其中柱子上有一堆盘子,盘子按从小到大的顺序叠放。现在的目标是将所有的盘子按大小顺序重新叠放在另一根柱子上。并且规定,任何时候,小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。我们该如何去实现呢?请列出移动步骤?
3. 题目分析
解题思路:我们需要把圆盘看成一个一个的整体,将大事化小,繁事化简。并假设三个柱子分别为A、B、C(A:起始柱,B:中转柱,C:目标柱)。实际上,解决汉诺塔问题是有规律可循的:
- 当起始柱上只有 n=1 个圆盘时,我们可以很轻易地将它移动到目标柱
- 当起始柱上有 n=2 个圆盘时,移动过程是:先将起始柱上的第 1 个圆盘移动到辅助柱上,然后将起始柱上剩下的圆盘移动到目标柱上,最后将辅助柱上的圆盘移动到目标柱上。
- 当起始柱上有 n=3 个圆盘时,会发现,移动过程和 n=2 个圆盘的情况类似:先将起始柱上的 2 个圆盘移动到辅助柱上,然后将起始柱上遗留的圆盘移动到目标柱上,最后将辅助柱上的圆盘移动到目标柱上。
图 1 移动两个圆盘
图 2 移动三个圆盘
通过分析以上 3 种情况的移动思路,可以总结出一个规律:对于 n 个圆盘的汉诺塔问题,移动圆盘的过程是:
- 将起始柱上的 n-1 个圆盘移动到辅助柱上;
- 将起始柱上剩下的 1 个圆盘移动到目标柱上;
- 将辅助柱上的所有圆盘移动到目标柱上。
由此,n 个圆盘的汉诺塔问题就简化成了 n-1 个圆盘的汉诺塔问题。按照同样的思路,n-1 个圆盘的汉诺塔问题还可以继续简化,直至简化为移动 3 个甚至更少圆盘的汉诺塔问题。
需要注意的是,在我们解决汉诺塔问题时,不能太过于深究圆盘移动的过程,一旦盘子数量较多,移动过程是极其复杂繁多的,容易把自己绕晕,我也不建议大家去理清移动过程。我们只需要理解汉诺塔的实现原理,运用大事化小,繁事化简的思想,就相对容易多了。
4. 代码实现
这里的递归限制条件为 n=1。
#include<stdio.h>
// 移动盘子函数
void Move(char star, char goal)
{
printf("%c --> %c\n", star, goal);
}
// 汉诺塔Hanno函数
void Hanno(int n, char star, char temp, char goal)
{
// 如果只有一个盘子,直接移动
if (n == 1)
{
Move(star, goal);
}
else
{
// 将 n-1 个盘子从起始柱移动到中转柱
Hanno(n - 1, star, goal, temp);
// 将剩余的一个盘子从起始柱移动到目标柱
Move(star, goal);
// 将之前移动到中转柱的 n-1 个盘子再从中转柱移动到目标柱
Hanno(n - 1, temp, star, goal);
}
}
int main()
{
// 定义起始柱、中转柱、目标柱以及盘子数量
char star = 'A';
char temp = 'B';
char goal = 'C';
int numDish = 3; // 盘子数量
// 调用移动盘子函数
Hanno(numDish, star, temp, goal);
return 0;
}
// 移动 2^numDish-1 次
5. 结语
希望这篇文章对大家有所帮助,如果你有任何问题和建议,欢迎在评论区留言,这将对我有很大的帮助。
完结!咻~