目录
首先我们先要了解递归,然后思考该怎样把递归用在汉诺塔问题上
什么是递归?
程序调用自身的编程技巧称为递归。通俗来讲一个函数自己调用自己,就叫做递归。它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大的减少了程序的代码量。
递归的结束条件
递归的主要思想就是大事化小。
递归的两个必要条件:1.存在限制条件,当满足这个限制条件时,递归将不再继续。
2.每次递归调用之后越来越解决这个限制条件。
大致了解玩递归后,我们要清楚什么是汉诺塔问题
汉诺塔问题
要求:三个大圆柱ABC,A圆柱上有n个盘子,一次只能移动一个,大的必须在小的上面,要把A的全部移动到C处,最后从上到下按从小到大排序,我们看一下规律
移动1层要1次
移动2层要3次
移动3层要7次
移动4层要15次......
我们拿4层举例
如上图所属,要移动4个饼到C处,要利用C先移动上面3层到B柱出,而要上面3层到B柱处,则又要利用B先把上面两层一道C柱处,一个复杂的问题,能被我们拆成一个一个小问题,这就是递归的思想。
详细的文字解释为:
当A有4层时,首先A作为起始站,B作为终点站,C作为中转站,我们可以把最下面的一层看做地面,先不动,把C当做中转站,把A上面3层通过C移动到B处,已知移动3层到另一个柱子上时需要7次,那么我们把A处的3层移动到B处,就需要7次,这时就是这样的情况:A有一层最大的,B从小到大排着3层,C空着。然后把A处的最大的移动到C处,只需要一次。最后把B最为起始站,C作为终点站,A作为中转站,再次移动3层,需要7次。这时我们就移动完成了,总共次数就是7+1+7=15
明白了汉诺塔移动原理,我们要开始着手写代码了,首先要定义一个n来表示饼的数量,定义三个char类型的柱子。
代码解释
int main()
{
int n = 4;//盘子数量
char a = 'A', b = 'B', c = 'C';//ABC代表三个柱子
HanNuoTa(a, b, c, n);
return 0;
}
// HanNuoTa(起始位置,中转位置,目的位置)
void HanNuoTa(char a, char b, char c, int n)
{
if (n >= 3)
{
HanNuoTa(a, c, b, n - 1);
printf("%c->%c\n", a, c);
HanNuoTa(b, a, c,n - 1);
}
else
{
swap(a, b, c);
}
}
然后,我们定义一个hannuota函数,后面接着的三个形参,分别表示我们的起始位置,中转位置,目的位置,第四个形参表示我们的层数。我们通过上述对4层汉诺塔问题的解析,我们设定递归结束条件为n=2,即只剩下两个柱子的时候,我们执行swap交换函数。
void swap(char a, char b, char c)
{
printf("%c->%c\n", a, b);
printf("%c->%c\n", a, c);
printf("%c->%c\n", b, c);
}
swap只做很简单的事情,它只把我们接收过来的abc三个参数,然后打印过程,先把a移动到b,然后把a移动到c,最后把b移动到c。这就是n=2的移动方式。
最后我们要写hannuota函数if(n >= 3)的内部代码了,通过之前的分析,我们知道首先要把a起始位置的n-1个饼通过c中转到b处,b是我们的目的地,所以我们要先写上HanNuoTa(a, c, b, n - 1);
这时我们在a处只留下了一个最大的底盘,要把底盘移动到c处,直接打上printf("%c->%c\n", a, c);
接着a处已经空了,b处有n-1个饼,c处只有一个最大的底盘,我们就可以通过a,把a当做中转站,把b处的n-1个饼移动到c处完成全部的移动。
这样就打完了我们全部的代码了,是不是通过了少量的代码实现了一个复杂的过程,这就是我们的递归。
结果展示
最后我们来看一下n=4的结果