汉诺塔是一道非常经典的问题了,这道题很好地考验了我们的思维能力,可以帮助我们进一步理解递归。
首先介绍一下汉诺塔问题的背景:
汉诺塔(Tower of Hanoi),又称河内塔,源于印度的一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
关键就在于小圆盘上面不能放大圆盘且每一只能移动一个盘子。
看似简单的问题其实内涵很深。
我们先从简单的来看:
假如只有一个盘子,那么只需要移动一次。
两个盘子:移法:A->B A->C B->C
三个盘子:移法:A->C A->B C->B A->C B->A B->C A->C
.......
往后就不容易想了,随着盘子增多,移动次数也在递增
1个盘子1次,2个3次,3个7次,那么10个就是2^10-1次,64个就是2^64-1次。
我们大概来算一下需要多久能移完这些盘子,假设婆罗门一秒能移动一个盘子并且每次移动无误,那么需要移18446744073709551615 次,也就是2^64-1秒,换算下来也就是大概5800多亿年......确实有点吓人了,没想到汉诺塔看似简单,实则如此复杂。
所以我们需要计算机来实现。虽然我算了下,凭我的电脑,算64层汉诺塔也得100多年......
话不多说,下面我们就用递归来实现它。
先创建一个函数来表示从柱子上移动盘子的过程:
void move(char pos1, char pos2)
{
printf(" %c->%c ", pos1, pos2);
}
然后创建函数实现汉诺塔的过程:
void Hanoi(int n, char pos1, char pos2, char pos3)
{
if (n == 1)
move(pos1, pos3);
else
{
Hanoi(n - 1, pos1, pos3, pos2);
move(pos1, pos3);
Hanoi(n - 1, pos2, pos1, pos3);
}
}
解释一下参数,pos1,2,3就分别对应A,B,C柱, n就是要移动的盘子的个数,(pos1,pos3,pos2)这边指移动的过程,第一个(pos1)是起始位置,第二个(pos3)是中转位置,第三个(pos2)是结束位置。
如果只有一个盘子时(n==1)就是从pos1移动到pos3 , 其他情况下都是先将上面n-1个盘子先借助C柱移到B柱上,Hanoi(n-1;pos1,pos3,pos2)
然后将A柱上的盘子移到C上。 move(pos1,pos3)
然后再借助A柱,将B柱上的盘子全部移到C柱上,Hanoi(pos2,pos1,pos3)
如此,就实现了整个程序。
来看完整代码:
void move(char pos1, char pos2)
{
printf(" %c->%c ", pos1, pos2);
}
void Hanoi(int n, char pos1, char pos2, char pos3)
{
if (n == 1)
move(pos1, pos3);
else
{
Hanoi(n - 1, pos1, pos3, pos2);
move(pos1, pos3);
Hanoi(n - 1, pos2, pos1, pos3);
}
}
int main()
{
Hanoi(1, 'A', 'B','C');
printf("\n");
Hanoi(2, 'A', 'B', 'C');
printf("\n");
Hanoi(3, 'A', 'B', 'C');
printf("\n");
return 0;
}
这里测试一下,当盘子个数为1,2,3,时的移动过程:
和我们自己移动的结果一样,代码正确。
等100多年以后我再来看结果吧^ ^