汉诺塔是递归的一个非常典型的问题。
汉诺塔问题的描述是:有三根柱子(A、B、C),A柱子上有n个圆盘(由下到上逐个减小),现在要将A柱子上的n个圆盘移到C柱子上,可以借助B柱子,要求小圆盘上不能放大圆盘,并且每次只能移动一个圆盘。
首先让我们分析一下汉诺塔问题,汉诺塔可以用递归解决,要完成递归算法我们需要找到两个要素①、递归出口;②、组成大问题的子问题。
1、递归出口
显然汉诺塔的递归出口是当n=1时,我们只需要将A柱子上的圆盘直接拿到C柱子上就可以了。
2、大问题的子问题
这里我们不妨用当n=2时来推断出其子问题的规律。
当n=2时(即A柱子上有两个圆盘要移动到C柱子上),我们需要做的是:
①:A----1---->B(将1号圆盘从A柱子移动到B柱子)
②:A----2---->C
③:B----1---->C
由此我们可以推断出汉诺塔的规律,即有n个圆盘时:
①:A----n-1---->B(将前n-1号圆盘由A柱子移动到B柱子上)
②:A----n---->C(将n号圆盘由A柱子移动到C柱子上)
③:B----n-1---->C(将前n-1号圆盘由B柱子移动到C柱子上)
得到两个递归条件之后我们可以写出递归算法的程序了,在这里笔者用C语言实现。
#include<stdio.h>
//递归函数(这里的想x可能是A柱子也可能是B柱子,y则与x在{A、B}柱子互斥,z则一定是C柱子)
//函数功能是借助y柱子将x柱子上的n个圆盘移到z柱子上
void hanoi(int n,char x,char y,char z) {
if(n==1) {//递归出口
printf("将编号为%d的盘子从%c柱子物体移动到%c柱子上\n",n,x,z);
}else{//小块循环
//将前n-1号圆盘由x柱子移动到y柱子上
hanoi(n-1,x,z,y);
//将n号圆盘由x柱子移动到z柱子上
printf("将编号为%d的圆盘从%c柱子物体移动到%c柱子上\n",n,x,z);
//将前n-1号圆盘由y柱子移动到z柱子上
hanoi(n-1,y,x,z);
}
}
int main(void) {
char A = 'A';//第一根柱子
char B = 'B';//第二根柱子
char C = 'C';//第三根柱子
int n;//需要移动圆盘的数量
scanf("%d",&n);//输入圆盘个数
hanoi(n,A,B,C); //调用递归函数
}
笔者认为汉诺塔问题比较抽象,我们要从分析递归问题的角度去解决汉诺塔问题,这样有利于我们快速掌握。还有一个扩展和大家分享一下(移动n个盘子的最少移动次数是:2^n - 1,大家不妨可以试一下)。使用递归就要用分治思想将要解决的问题简单化,“分治”是解决问题的战略思想,“递归”是编程中的战术手段。