先来描述一下什么事汉诺塔问题?
相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到B杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
这是程序语言递归算法的经典问题,今天终于在实际操作中大彻大悟,理解了其中的递归算法的真正含义。话不多说,直接上代码,让我们先看一下c++代码是如何实现的。
#include <iostream>
/* 汉诺塔递归算法:通过反复调用函数,使问题逐渐简化。 */
using namespace std;
int main()
{
void hanio(int n,char a,char b,char c);
int n;
cout << "请输入有几个座" << endl;
cin>>n;
cout<<"移动的步骤为:"<<endl;
hanio(n,'a','b','c');
return 0;
}
//搬动n个盘,从a到b,c为中间过渡
void hanio(int n,char a,char b,char c)
{
if(n==1)
{
cout<<a<<"---->"<<b<<endl;
}
else
{
hanio(n-1,a,c,b);//将前n-1个盘子移到c的位置上
cout<<a<<"---->"<<b<<endl;//将最后剩余的最大的一个放到b上
hanio(n-1,c,b,a);//将c上之前放的n-1个放到b上
}
}
这里我在第一次看到这个代码的时陷入了一个误区,看不明白其中这一步hanio(n-1,a,c,b);
是将前n-1个盘子移到c的位置上。
然后是这一步cout<<a<<"---->"<<b<<endl;
是将最后剩余的最大的一个放到b上。
最后hanio(n-1,c,b,a);
是将c上之前放的n-1个放到b上,就完成了全部操作。
看完之后我就在思考,这样写真的可以吗,直到我自己敲出来之后真的可以实现,然后我就陷入到了其中思考计算机是怎么一步一步实现的而去理解这个递归算法。
其实这里我就是陷入了误区,试图去一步一步推出来这个算法的一步一步实现过程,然而或许3个盘子,4个盘子可以推出来,再多根本就是一团乱。
**事实上递归程序的关键点只在于两点:
1、归纳出递归的式子,就是归纳出要实现结果的规律。
2、确定递归的尽头。**
而我们很容易陷入到去理解计算机是如何一步一步实现的,其实完全不用,我们只需要归纳出规律即可,好下面让我们来看一看这个汉诺塔算法的规律究竟是什么?
我们先来考虑只有一个盘子的情况(很简单只有一步就可以):
第一步:从A移到B上就完成了这个问题
接着我们来考虑两个的盘子的问提(也很简单三步就可以完成):
第一步:将第一个盘子从A移到过渡座C上。
第二步:将第二个盘子从A移到B上。
第三步:将第C上的盘子移回到B上。
可能现在还看不出规律接着我们来看一下三个盘子的问题:
第一步:把前n-1个盘子也就是2个盘子从A移到C上
1:将第一个盘子从A移到B上。
2:将第二个盘子从A移到C上。
3:将第B上的盘子移回到C上。
第二步:把最下面的盘子也就是第三个盘子从A移到B上
第三步:把n-1个盘子从C上的位置移回到B上
1:将第一个盘子从C移到A上。
2:将第二个盘子从C移到B上。
3:将第A上的盘子移回到B上。
这里我们就可以看出来规律了,移动三个盘子其实就是重复了两遍移动两个盘子的步骤然后加了一步把最大的从A移到B的过程,这里注意当最大的盘移动到B上时,我们就不需要思考他了,因为他是最大的盘,如果把这时的C座看为A座相当于就把三个盘的问题转换成了两个盘的问题。就是这个关系就把三个盘的问题变成了2个盘的问题,按照这种思想,那么4个盘的问题也可以转变成3个盘,然后这不正是递归算法吗?