开篇语
我们已经学习了函数递归,并且上期详细介绍了函数的递归和迭代各自的优缺点,可能函数递归是学到现在目前是一个较为难的点,所以这期专门找来几道经典例题来重点强化学习一下递归。这期呢,一共三个问题,汉诺塔问题,斐波那契数列,青蛙跳台阶问题,后两个是相对来说比较简单并且很相似的问题,我们先来看简单的。
斐波那契数列
关于斐波那契数列数列呢,我们在专门一期函数的递归与迭代中做了详细论述,这里我们只做简单复习,为青蛙跳台阶问题作一下铺垫就好。如果有没有看过的呢,传送门也放在这里,把经典例题一定一定一定要弄懂,传送门C语言底层逻辑剖析函数篇(其三),函数递归与迭代超详解,斐波那契数列递归经典例题。
题目要求:求第n个斐波那契数;
我们用递归的思想就是要求第n个斐波那契数,我们只有把第n-1和第n-2个斐波那契数求出来相加即可,代码如下:
#include<stdio.h>
int Fib(int n)
{
if (n <= 2)
{
return 1;
}
else
{
return Fib(n - 1) + Fib(n - 2);
}
}
int main()
{
int n = 0;
scanf("%d",&n);
int ret = Fib(n);
printf("%d\n",ret);
return 0;
}
我们只需要回忆一下递归基本思路即可;下面我们来看与斐波那契数列相似的青蛙跳台阶问题。
青蛙跳台阶
题目:(1)一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级。求该青蛙跳上一个n 级的台阶总共有多少种跳法。
我们先来简单分析一下,分析如下:
有了这个思路,这个题看起来就似曾相识的感觉,没错,这题目本质上就是一个斐波那契数列,所以我们的代码也就很好的就出来了:
//青蛙跳台阶问题
#include<stdio.h>
int num(int n)
{
if (n == 1)//当只有一层台阶时
{
return 1;
}
else if (n == 2)//当只有两层台阶时
{
return 2;
}
else
{
return num(n - 1) + num(n - 2);
}
}
int main()
{
int n = 0;
scanf("%d",&n);
int ret = num(n);
printf("一共有%d种跳法\n",ret);
return 0;
}
这个相对来说也非常简单。我们接下来就是重头戏了
汉诺塔问题
汉诺塔问题绝对是递归里面最最最经典的例题之一,但是想要真正理解是非常困难的,我们先来看题目:
汉诺塔问题,是心理学实验研究常用的任务之一。. 该问题的主要材料包括三根高度相同的柱子和一些大小及颜色不同的圆盘,三根柱子分别为起始柱A、辅助柱B及目标柱C。. [1] 中文名. 汉诺塔问题. 外文名. tower of Hanoi. 来 源. 古印度汉诺塔游戏.
我们的目标是把A柱子上的圆盘一次移动一个全部移动到C柱上。
如果题目都没读懂没关系我们画图来解释:
那么我们A上有n块石板呢?我们相同的道理就应该,先把A上面n-1层石板挪到B柱上面,再把A柱最后一个挪到C上面,这时候问题就变成了,把B上面的n-1个石板挪到C上面去,依次往复下去;
道理是懂了,但是现在如果让你去写代码可能还是写不出来,所以我只能把代码放出来来帮助大家理解:
//汉诺塔问题
#include<stdio.h>
void hanoi(int n,char A,char B,char C)
{
if (n == 1) //当只有一个圆盘时
{
printf("%c->%c\n",A,A);
}
else
{
hanoi(n - 1, A, C, B);//把n-1个圆盘从A绕过C挪到B上
printf("%c->%c\n",A,C);//把A底下那个圆盘挪到C上
hanoi(n-1,B,A,C);//问题变成了把n-1个圆盘从B挪到C上,这样递归下去;
}
}
int main()
{
int n = 0;
scanf("%d",&n);
hanoi(n,'A', 'B', 'C');
return 0;
}
第一遍看不懂也没关系,这个确实是很难理解,再把思路理清重新看几遍,理解不了也不必强求,这里温馨提示一下,我们解释的时候是把圆盘挪动,但是在代码里面变量定义的参数是确定死的,实际上来回交换的是三根柱子,我之后还会出一期关于函数栈帧的详细解释,每一个变量是怎么创建的,怎么在内存中分配的,函数是怎么一步步调用的,等等非常偏底层的这些问题都会迎刃而解,学习这些相当于修炼内功,对代码的理解能力能够提升非常多。看我函数栈帧之后再来看汉诺塔这个问题一定会有不一样的认识。