递归:这个词简直是大多数初学者的噩梦,当初学者在接触递归时,简直是一头雾水,很难理解,这是正常的,因为我们都不是天才,主要原因呢还是归功于不理解递归在底层到底发生了什么,而是只看表面,当然就很难明白递归到底是怎么一回事,但当能明白底层发生了什么,基本也就不难理解了。
一、递归的介绍:
C语言中的函数都支持递归,递归换句话说就是自己调用自己,递归分为直接调用自己跟间接调用自己,其实只要直接调用自己能理解了,间接调用也就不在话下了。
二、递归的实现:
递归之所以能实现,就是因为函数在运行时在栈中都有自己形参和局部变量的副本,而这些副本与该函数的执行过程不发生任何关系,因为这种机制递归才能实现。
举一个大众都知道的,阶乘n!的例子,程序如下:
#include
int f(int n)
{
if(n>0)
return n*f(n-1);
else
return 1;
}
int main()
{
int mul;
scanf('%d',&mul);
printf('%d',f(mul));
{
比如输入的数字为3,当执行递归函数时,数字3被赋给形参n,此时会产生一个形参的副本,数字3会被送到栈中(栈就像一个容器,有先进后出的特性),而后由于3大于0,执行随后的语句:return n*f(n-1)语句,此处为调用点,虽然执行到return语句,但是不会结束,还会继续调用f(n-1),就是f(2),而后形参2,也被送入到栈中,通过f(2)函数里的条件判断语句,依然得到n>0,,继续上面的过程,直到n=0,然后返回1,函数不会在调用自身,自此栈中的数据为:栈顶0,3在最下面,至此就可以逐层返回,因为最后面的return n*f(n-1),并没有执行结束,上面的只不过在逐层调用,此时就开始返回,从栈顶开始,使用它自己的变量,一旦使用过就立即销毁,先得到0,由return 1语句就得到f(0)=1,至此栈中的0就被销毁,然后再返回到上一层,执行f(1)中return f(0)*n,此时栈顶的数值为1(那么n=1),因此f(1)返回1,此时栈顶的1立即被销毁,而后在返回到上一层f(2)中return f(1)*n,此时栈顶的数值为2,那么f(2)返回数值2,栈顶数值2被销毁,依次上面的过程,直到f(3)返回6,最后直到推出,结束递归。
其实上面的过程可以变形为:
int f(n)
{
if(n>0)
return n*{if((n-1)>0) return (n-1)*{if((n-2)>0) return (n-2)*{if((n-3)>0) return (n-3)*{……直到n=0返回1时}}
从上面看出多个return逐层返回,其实即使没有return也能返回,因f(n)一条语句可以分成若干语句,直到有一个结束调用自身的条件,算了,不多说了,多说的话,很可能越看一蒙蔽,其实概括一下,如果某个函数调用了本身,而本身其实里面又包含了自身,也就是又调用了自身,第二次调用时就称为调用函数的递归,一直调用到符合结束条件后,就逐层返回,然后才能执行到最后,就像上面的逐层返回的return,直到最后一个return。
其实只要找到f(n) 跟f(n-1)等之间的关系,就可以使用递归关系,在结合底层栈中的数据变化,跟踪分析,多练练,递归也就能运用自然,但是从上面分析可以看出,递归次数越多程序运行时占用的内存就越多,甚至会产生溢出,依次使用递归往往会使程序效率降低,因此一般不建议使用递归,因为所有递归都可以使用非递归的方法解决,但是递归也有递归的优点,并不是一无是处(如效率影响不大或维护性可读性较非递归时更好),所以是不是用递归要视情况而定。
上面就是关于函数递归的介绍,也许我的表达能力不太好,讲的不具体,但已尽力,下一篇要是有想到更好的讲解方式将会继续。