尾递归使用的详细说明
尾递归概念
尾递归的概念(尾递归)是递归的一个子概念。普通递归的调用堆栈的使用是不可估量的因为需要记住的递归调用堆栈。例如,在下面的PHP部分的第一个例子使用PHP写的一个阶乘函数,这是由于对由于递归栈溢出错误,尾递归的目的是消除递归栈的缺点。
从代码级别来说,尾递归实际上使它变得清晰:
函数的最后一个操作是递归调用。
例如,feibona递归实现PHP楔形阵:
复制代码代码如下所示:
fibonacci.php
< PHP
函数斐波那契(n){
如果($<2){
返回n;
}
回报斐波纳契(N - 1)+斐波那契(N - 2);
}
var_dump(斐波那契(30));
这是一个递归函数,但不是尾递归,因为斐波那契的最后一个运算是加法运算。
转尾递归:
复制代码代码如下所示:
功能fibonacci2(美元美元美元,ACC,ACC){
如果($ = 0){
返回的ACC1;
}
返回fibonacci2($ n-1,ACC2美元美元美元,ACC1 + ACC2);
}
fibonacci2是尾递归,这增加了两个累加器,ACC1和ACC2,给出初始值。记住:递归尾递归要增加蓄电池和减少递归操作的思路。
尾递归在不同语言中的应用也是不同的,函数编程Erlang最常用的是几乎所有递归函数都被转换成尾部递归,下面是几个不同语言中尾递归的性能和应用的几个例子。
PHP中的尾部递归
我们做一个实验
常见的递归:
复制代码代码如下所示:
< PHP
函数阶乘(n)
{
如果($ = 0){
返回1;
}
返回阶乘(n-1)* n;
}
var_dump(阶乘(100000000));
尾递归:
复制代码代码如下所示:
< PHP
函数阶乘($ n,ACC)
{
如果($ = 0){
返回$;
}
返回阶乘($ n-1);
}
var_dump(阶乘(100000000, 1));
实验结果:
事实证明
PHP中的尾部递归没有任何优化效果!
c中的尾递归
在C语言中进行尾递归优化,在GCC编译时加入O2,对尾递归进行优化。
我们可以直接查看生成的汇编代码:
(使用gdb,gcc -O2阶乘。C O因子;解体因子)
不是由O2生成的汇编程序:
O2优化汇编:
没有大头,我也是第一个看汇编的,但是这个代码很简单,可以在线搜索一点命令,大致理解:
复制代码代码如下所示:
功能因素(N,总和){
而(n)!= 0){
总和=n和
n = n
}
收起回复
}
GCC做的是智能优化。
如果您感兴趣的话,您可以使用O3优化尾部递归,并查看其中的汇编指令。
臭氧的优化是直接扩展循环。
总结
一般的线性递归修改尾递归的最大优势是减少递归调用堆栈的开销。从PHP实例,递归的开销对方案的影响显而易见。但并不是所有的语言都支持尾递归,甚至支持尾递归语言一般是在编译时优化尾递归优化如尾递归C语言。当尾递归是用来优化代码,你必须首先了解尾递归语言的支持。