读码农翻身之递归

1、什么是递归:
读码农翻身之递归
如上所示,这是一个递归函数,所为递归,就是一个函数调用了自己。或者说一个函数在函数内部调用了另一个函数,而这另一个函数的功能和本身这个函数的作用一样。虽然从理论上来说,这样确实是讲得通的,那么作为最终要在计算机中执行的程序,在内存中是什么样的呢?
读码农翻身之递归
当代码编译以后,函数会被放在代码段。(只有一套代码放在代码段!)而上图中的栈帧就代表了被调用中的一个函数,这些函数栈帧以先进后出的方式排列起来,形成了一个栈,而每个栈帧的详细信息其实如下所示:
读码农翻身之递归
那么意思就是每次调用一个函数,就会在栈中压入一个栈帧,那么假如计算啊factorial(4)这个函数的时候,那么实际上就会有4个栈帧,如下所示:
读码农翻身之递归
读码农翻身之递归
每个递归函数必须有个终止条件,要不然就会发生无限递归。同时,由于堆栈容量也是有限的,如果N的值太大,那么就需要更多的栈帧。
那么这里做个试验,以上述的函数为例,通过更改N的值,来看看效率到底如何:
读码农翻身之递归
而当N的值设置为3000时,已经出现了栈溢出了。所以使用这种递归算法,如果N的值过大,还是很容易让程序异常的。
读码农翻身之递归

2、递归的优化算法(尾递归)
读码农翻身之递归
这个优化后的算法和优化前的算法进行对比,函数的最后一个语句,不在是n*fun(n-1),而是直接调用fun()函数本身,那么这个算法的计算过程就是:
读码农翻身之递归
而此时计算机在内存中是怎么计算的呢?
读码农翻身之递归
这就是很妙的地方了,相对于旧的算法,新的算法只是一个函数,那么就意味着只有一个栈帧。
但是通过我实际操作,发现N为3000的时候,尾递归还是会抛出栈溢出。

难道是这种所为的尾递归并没有作用?