尾递归就是从最后开始计算, 每递归一次就算出相应的结果, 也就是说, 函数调用出现在调用者函数的尾部, 因为是尾部, 所以根本没有必要去保存任何局部变量,直接让被调用的函数返回时越过调用者。
比如计算n!
LL fac(int n,LL ans)
{
return n == 1 ? ans:fac(n-1,ans*n);
}
上面的递归过程如下:
fac(5, 1)
fac(4, 5)
fac(3, 20)
fac(2, 60)
fac(1, 120)
120
很容易看出, 普通的线性递归比尾递归更加消耗资源, 在实现上说, 每次重复的过程调用都使得调用链条不断加长. 系统不得不使用栈进行数据保存和恢复。而尾递归就不存在这样的问题, 因为它的状态完全由n和ans保存.
经过实践证明尾递归要比传统的递归方法快得多。
LL fib(LL last,LL ans,LL cur,LL n)
{
if(n == 1 || n == 2) return 1;
if(cur == n) return ans;
return fib(ans,ans+last,++cur,n);
}
比如,我们计算第6个Fib数的值,那么尾递归的调用过程为:
fib(0,1,0,6)
fib(1,1,1,6)
fib(1,2,2,6)
fib(2,3,3,6)
fib(3,5,4,6)
fib(5,8,5,6)
fib(8,13,6,6)
最终输出13