理解递归的含义
理解递归的含义是我们熟练运用递归的前提,首先,什么是递归?递归即是指函数、过程、子过程在运行过程中直接或间接调用自身而产生的重入现象。简单来说,递归思想即是在方法中自我调用的过程。它可以使处理一些重复性工作的思路更加清晰。
小试牛刀
理解了递归的含义之后,我们可以将这个思想体现在我们的代码中,以下我会用一个经典递归实例猴子吃桃来对递归思想进行进一步的说明。
题目:猴子第一天摘了若干个桃子,当即吃了一半,还不解馋,又多吃了一个;第二天,吃剩下的桃子的一半,还不过瘾,又多吃了一个;以后每天都吃前一天剩下的一半多一个,到第10天想再吃时,只剩下一个桃子了。问第一天共摘了多少个桃子?
由以上题目,我们可以发现,这是一个机械重复的过程,对于此种类型的过程,使用递归思想,可以使得代码大大地简化。以下开始解题。
已知猴子每天吃的桃子是前一天剩下桃子的一半多一个。于是由此关系,我们可以得出此递推式:f(n) = (f(n+1)+1)*2
解释:f(n)表示第n天剩下的桃子,其数目与第n+1天的桃子数有关。此关系式正好是确定这两者关系的式子。这个问题就变成了已知f(10)=1和递推式f(n) = (f(n+1)+1)*2,求f(1)的问题。根据此递归式,我们可以写C语言代码如下:
#include <stdio.h>
int f(int n)
{
int c = 0;
if(n == 10) //递归出口,从此开始返回计算
return 1;
else
c = (f(n + 1) + 1) * 2; //调用自身,注意,此调用和自身函数名相同,属于递归调用。
return c;
}
int main()
{
int c = f(1);
printf("第一天共摘了 %d 个桃子\n",c);
return 0;
}
问题一:这个函数是如何运行的?
递过程:
开始,n=1进入此函数中,判断发现,n不等于10,于是,执行else中的代码,即:f(1) = (f(2)+1)*2,而此时,f(2)进行了自身的函数调用,即利用f(n)函数算出了f(2)后,代入此式子中,计算f(1)。所以,应先计算f(2)。
n=2进入此函数中,判断发现,n不等于10,于是,执行else中的代码,即:f(2) = (f(3)+1)*2,而此时,f(2)进行了自身的函数调用,即利用f(n)函数算出了f(3)后,代入此式子中,计算f(2)。有了f(2)再代入到f(1) = (f(2)+1)*2中计算f(1)。所以,先计算f(3)。
…
归过程:
n=10进入此函数中,判断发现,n等于10,于是,执行return 1,返回f(10) = 1到
f(9) = (f(10)+1)*2中,计算出f(9)=4,返回f(9)=4到f(8) = (f(9)+1)*2,计算出f(8),…最后计算出f(1)。此为答案,输出即可。
问题二:计算结果?
计算结果如下:
第一天共摘了 1534 个桃子
对于递归思想的评价
从以上例子中我们可以看出,递归思想非常适用于诸如此类有着机械重复动作的问题,这样可以使得自己的代码大大简化,但是,从例子中也可以看出,递归过程中,既有递过程,又有归过程,而且二者都是循环过程,所以,虽然代码大大简化,但是带来的计算量却是单次循环的两倍,大大增加了计算负担,降低了运行效率。在此例子中,数据量还不算大,所以用递归其运行效率和普通循环的运行效率没有明显的差异,但若数据量稍稍过大,差距就异常明显。所以递归思想在数据量大的时候谨慎使用!