一、问题描述:Hanoi塔是什么
假设有3个分别命名为A、B和C的塔座,在塔座A上插有n个直径从上至下从大到小的圆盘,编号为1,2,…n。现要将A轴上的n个圆盘移至塔座C并按照同样的顺序叠排。
- 每次只能移动一个圆盘。
- 圆盘可插在A、B和C中任一塔座上。
- 任何时刻都不能将一个较大的圆盘压在较小的圆盘上。
二、解决思路
1 简单案例
先来解决n较小时,n = 3时的情况:
如图我们可以轻易解出:
step1:将A上1号盘移至C,step2:将A上2号盘移至B,step3将C上1号盘移至B,step4:将A上3号盘移至C,step5:将B上1号盘移至A,step6:将B上2号盘移至C,step7:将A上1号盘移至C;完毕。
2 步骤分析
如上案例,我们可发现,当n=1时,只要将A上1号圆盘移至C即可,而n>1时则需要将第n号盘上n-1个盘借助C移动至B,再将n号盘移至C上,而此时B上的n-1号盘上n-2个盘又可借C移至A,而第n-1号则可移至C,此时状态如下
从中我们不难发现,此时又回到了初始状态,又可通过同样的方法将第n-2号移至C上。是一个很典型的递归算法。
3.伪算法
据上述归纳分析可写出如下递归伪算法(引用《郝斌数据结构》)
if(n>1)
{
先把A柱子上的前n-1个盘子从A借助C移至B
将A柱子上的第n个盘子直接移到C
再将B柱子上的n-1个盘子借助A移至C
}
三、具体代码
#include <stdio.h>
void move(char A,int n,char C) {
printf("\t将%d号盘从%c移至%c\n", n, A, C);
};
void hanoita(int n, char A, char B, char C) {
if (n == 1)
move(A, 1, C);
else {
hanoita(n - 1, A, C, B); //n>1时将1至n-1号盘借助C移至B
move(A, n, C); //将n号盘移至C
hanoita(n - 1, B, A, C);// 将B上1至n-1号盘借助A移至C,这里看作一个位置循环ACB,BAC,即将
// B赋给下个递归函数的A,就可以将n-1个盘分解为n-1号盘与n-2个盘,循环递归。
}
}
int main() {
int num = 0;
char A='A', B = 'B', C = 'C';
printf("*******汉诺塔问题*******\n");
printf("初始A柱上有圆盘数:n = ");
scanf_s("%d", &num);
printf("\n步骤如下:\n\n");
hanoita(num, A, B, C);
}
运行结果
不然发现其步骤次数为:
2
n
−
1
2^n-1
2n−1,n为初始圆盘的个数。