昨天我总结函数递归说到了两个例子,今天我们就来看一下其中之一汉诺塔
汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
2020年8月3日,夏焱以33.039秒的成绩成功打破6层汉诺塔吉尼斯世界纪录。
2021年5月16日,中国龙岩的陈诺以29.328秒的成绩打破了6层汉诺塔吉尼斯世界纪录。
汉诺塔是一种经典的逻辑游戏,也是计算机科学领域中经典的算法问题。 这个游戏由三个竖立的柱子和一些不同大小的圆盘组成,开始时所有的圆盘都堆叠在柱子A上,而其他两个柱子则为空。 游戏的目标是将所有的圆盘从柱子A移动到柱子C上,每次只能移动一个圆盘,并且大圆盘不能放在小圆盘上面。
根据汉诺塔的介绍,若把A柱子移动到C柱子,我们可以知道一结论
1.每次只能移动A柱最上面的一个盘子。
2.小盘子上不能放大盘子。
我之前总结道函数递归思想是把大规模事化小规模事的过程,并且都含有一个相同规律点从而不断化小下去,所以我们先假设n为一个数。
大家都能看出来直接将A--->C
我们可以看出要分三步,首先A最上面红色块先到B,再把A最下面那个大的绿色块直接到C,最后把移动到B的红色块再移动到C,相当于A借助B到C
1.A--->B
2.A--->C
3.B--->C
此时一眼难看出来,那我们可以这样分析一下,把A拆分成上面两个和下面一个大的,上面两个先从A到B重复n=2的过程,此时是将那2个盘子从A借助C移动到B
A--->C
A--->B
C--->B
再将A最下面那个大的移动到C,
A--->C
最后将B上的两个再移动到C上也是类似于n=2的操作,此时两个盘子从B借助A移动到C
B--->A
B--->C
A--->C
此时我们更难一眼看出来,那我们继续用上一个的思路继续拆分把上面的三个看成一个整体,最下面那个大的看成一个整体,上面三个重复n=3的过程,只不过此时是A借助C移动到B
A--->B
A--->C
B--->C
A--->B
C--->A
C--->B
A--->B
接着我们再把那块大的盘子移动到C上
A--->C
最后将B上的3个盘子移动到C上,重复n=3时的步骤,只不过此时是我们此时是B借助A把移到C
B--->C
B--->A
C--->A
B--->C
A--->B
A--->C
B--->C
到现在为止我们是不是隐隐约约发现了规律点,没错,都是将最下面那块最大的盘子看成一个整体,然后上面为一个整体,所以可以把他们看成1和n-1两个整体。
通过以上观察,我们可以大致分成三步:
1.将A上n-1层的盘子借助C移动到B上
2.将此时A上剩余的盘子移动到C上
3.将B上此时n-1层的盘子借助A移动到C上(这三点非常重要!!!)
首先在main函数里规定一个Hanoi函数,这个函数用来表示汉诺塔整个过程,根据汉诺塔的玩法其实整个过程就是将初始A上的盘子通过B移动到C上
所以需要调用的实参就是三个柱子A,B,C以及初始在A上的n个盘子
int main()
{
int n = 0;
printf("输入A柱子上的盘子个数:");
scanf("%d", &n);
//将n个盘子从A柱借助于B柱移动到C柱上
Hanoi('A', 'B', 'C', n);
return 0;
}
在Hanoi函数内部,我们首先要分情况讨论,如果n=1时,我们是不是只需要将A--->C(A移动到C)移动需要创建一个move函数,只有n>1时才符合我们得出的结论,然后再按照结论得出的三步骤,根据我们得到的结论我们是不是可以发现我们的结论符合Hanoi函数递归的条件从而不断重复这三个步骤,直到n减到1,走第一个分支语句从而结束递归(这一步要好好品味一下!!!)
void Hanoi(char A, char B, char C, int n)
{
if (n == 1)
{
Move(A, C, n);
}
else
{
//将n-1个盘子从A柱借助于C柱移动到B柱上
Hanoi(A, C, B, n - 1);
//将A柱最后一个盘子移动到C柱上
Move(A, C, n);
//将n-1个盘子从B柱借助于A柱移动到C柱上
Hanoi(B, A, C, n - 1);
}
}
void Move(char A, char C, int n)
{
printf("把第%d个盘子从%c--->%c\n", n, A, C);
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
void Move(char A, char C, int n)
{
printf("把第%d个盘子从%c--->%c\n", n, A, C);
}
void Hanoi(char A, char B, char C, int n)
{
if (n == 1)
{
Move(A, C, n);
}
else
{
//将n-1个盘子从A柱借助于C柱移动到B柱上
Hanoi(A, C, B, n - 1);
//将A柱最后一个盘子移动到C柱上
Move(A, C, n);
//将n-1个盘子从B柱借助于A柱移动到C柱上
Hanoi(B, A, C, n - 1);
}
}
int main()
{
int n = 0;
printf("输入A柱子上的盘子个数:");
scanf("%d", &n);
//将n个盘子从A柱借助于B柱移动到C柱上
Hanoi('A', 'B', 'C', n);
return 0;
}
生成结果:
这个问题不好让人理解,我已经把我所表达的都表达了,哈哈哈尽力理解吧,加油!!!
有什么问题各位大佬多评论谢谢