文章目录
一、前言
汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
二、具体操作
首先我们假设三根柱子分别叫A,B,C。
汉诺塔的操作是为了将A上所有的圆盘移到C上,但移动过程中,每次只能移动一个圆盘,且整个过程中大圆盘下面不能有小圆盘
一层汉诺塔时,只需将A上圆盘移至C上,记作: A->C(将A上圆盘移一个至C)
二层汉诺塔时,操作记作:A->B , A->C , B->C
此时我们可以先将B视为C,C视为B。则第一步也就是第一层汉诺塔的操作,(回到最初对三根柱子的定义)然后将A上大圆盘移至C,最后将B视为A,A视为B,则最后一步也是一层汉诺塔的操作。
三层汉诺塔时,操作记作:A->C , A->B , C->B , A->C , B->A , B->C , A->C
我们如果先将上两层的圆盘移至B,再将第三层的圆盘移至C,那么问题就会变成将A视为B,B视为A的二层汉诺塔问题。
B->A , B->C , A->C ⇒ A->B , A->C , B->C
而之前将上两层的圆盘移至B,如果将B视为C,C视为B。则又变成了两层汉诺塔的问题。
A->C , A->B , C->B ⇒ A->B , A->C , B->C
之后的操作都是如此,我们只需将问题每次拆成先将最下面的圆盘和他上面的圆盘两部分,分别在A和B上,再将最大的圆盘移至C上,则又回到了前一层汉诺塔的问题。
此时我们就可将汉诺塔问题视为递归的问题,n层的操作就是先将B视为C,C视为B执行n-1层的操作,再将A柱上最大的圆盘移至C。最后将A视为B,B视为A执行n-1层的操作。
这也就解释了为什么每层汉诺塔最少的操作步数是2^n - 1了,第n层的步骤就是2倍的第n-1层步骤的两倍 + 1。
三、实现代码
#include<stdio.h>
void Hanoi(int n, char A, char B, char C)
{
if (n == 1)
{
printf("%c->%c ", A, C);
}
else
{
Hanoi(n - 1, A, C, B);//将B视为C,C视为B
printf("%c->%c ", A, C);
Hanoi(n - 1, B, A, C);//将B视为A,A视为B
}
}
int main()
{
int n = 0;
printf("请输入汉诺塔的层数:>\n");
scanf("%d", &n);
Hanoi(n, 'A', 'B', 'C');
return 0;
}
四、总结
汉诺塔的问题仍旧是利用递归的思想,找到拆分的点,然后将第n层的问题联系到第n-1层解决,化大为小。
同样我们也要注意递归使用的两个必要条件:
1.存在限制条件,当满足这个限制条件的时候,递归便不再继续。
2.每次递归调用之后越来越接近这个限制条件。