目录
什么是汉诺塔?
如何分析汉诺塔
代码实现汉诺塔
什么是汉诺塔?
这是一个古典的数学问题,是一个用递归方法解题的典型例子。汉诺塔的故事在这里不做介绍啦!
汉诺塔的思想是:
总共有3根柱子,这里假设为A、B、C。A上有n个圆盘,圆盘的大小由下到上依次递减,现在我们要把这n个盘子借助B从A移动到C,但是每次只允许移动一个盘,且在移动的过程中在3个柱子上的盘都始终保持大盘在下,小盘在上。
如何分析汉诺塔
实质:将A上的圆盘借助B移动到C。
条件限制:(1)每次只移动一个 (2)小在上,大在下
在这里,我们选取n=3来分析。
(这里假设三个圆盘从上到下标号为123)
Step1:首先, C为辅助,B为目标。将1,2,即n - 1个圆盘移到了B柱上,C 柱为空,A 柱还剩下一个最大的盘子。
将盘子1从A -> C
将盘子2从A -> B
将盘子1从C -> B
在这一步之后,A上有3,B上有12,C为空。
Step2:将最大的盘子移动到了目标柱 C 上
将盘子3从A -> C
在这一步之后,A为空,B上有12,C有3。
两步之后,我们已经成功把3,移动到了我们想要放置的位置。
接下来用相同的方法,把2移动到C上。
Step3:此时 A 为辅助,C 为目标。将1,即n - 1个圆盘移到了A柱上,B柱还剩下一个最大的盘子。
将盘子1从B -> A
在这一步之后,A上有1,B为2,C上有3。
Step4:将当前最大的盘子移动到了目标柱 C 上
将盘子2从B -> C
在这一步之后,A上有1,B为空,C上有23。
又两步之后,我们已经成功把2,移动到了我们想要放置的位置。
Step5:此时 B为辅助,C 为目标。但此时,只剩一个盘子,我们可以直接将盘子移动到C上。
将盘子3从A -> C
在这一步之后,A为空,B为空,C上有123。
至此,完成了圆盘的移动。
小结:
从上面的分析我们可以看出,空的柱子为辅助,且两个步骤为一组(可以将一个圆盘正确的移动到目标柱C上)。于此,我们可以推到n个圆盘,每次借助辅助放置n-1个盘。
因此,不难看出,汉诺塔的问题本身是一个大问题,我们可以将这个大问题转化为许多个相似的小问题,其解决方案与将一个较小的汉诺塔移动到另一个柱子上的解决方案相似。这里我们就需要用到递归了。
代码实现汉诺塔
#include<stdio.h>
int main()
{
void hanoi(int n,char disA,char disB,char disC); //对hanoi函数进行声明
int n;
printf("输入一个整数n表示汉诺塔上圆盘的个数:");
scanf("%d",&n);
printf("汉诺塔的移动顺序:\n");
hanoi(n,'A','B','C');
return 0;
}
void hanoi(int n,char disA,char disB,char disC)
{
void move(char x,char y);
if(n==1) //只剩一个盘子
{
move(disA,disC); //将A移动到C
}
else
{
//将disA上的前n-1个圆盘(即除了最大的那个圆盘之外的所有圆盘)移动到辅助柱子disB上
//实际上是借助了disC辅助
hanoi(n-1,disA,disC,disB); //Step1 这一步之后,disA上剩一个最大的圆盘n ,disB有n-1个
move(disA,disC); //Step2 我们要将这个最大的圆盘n 移动到disC上 ,这一步之后,disA为空
hanoi(n-1,disB,disA,disC); //Step3 以此递归,将空的disA作为辅助
}
}
void move(char x,char y)
{
printf("%c-->%c\n",x,y);
}
最后我们来总结一下,什么时候会使用到递归思想来解决问题呢?
问题可以自然地分解为与原问题相似但规模更小的子问题时。同时要注意递归终止的条件。
然而,需要注意的是,递归可能导致大量的函数调用和返回,如果递归深度过大,可能会导致栈溢出等问题。因此,在使用递归时,需要仔细考虑其效率和安全性。