尾递归优化
Posted feng9exe
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了尾递归优化相关的知识,希望对你有一定的参考价值。
尾递归优化是利用上面的第一个特点“调用同一个方法”来进行优化的
尾递归优化其实包括两个东西:1)尾递归的形式;2)编译器对尾递归的优化
尾递归的形式
尾递归其实只是一种对递归的特殊写法,这种写法原本并不会带来跟递归不一样的影响,它只是写法不一样而已,写成这样不会有任何优化效果,该爆的栈和帧都还会爆
具体不一样在哪里
前面说了,递归的本质是某个方法调用了自身,尾递归这种形式就要求:某个方法调用自身这件事,一定是该方法做的最后一件事(所以当有需要返回值的时候会是return f(n),没有返回的话就直接是f(n)了)
要求很简单,就一条,但是有一些常见的误区
这个f(n)外不能加其他东西,因为这就不是最后一件事了,值返回来后还要再干点其他的活,变量空间还需要保留
比如如果有返回值的,你不能:乘个常数 return 3f(n);乘个n return n*f(n);甚至是 f(n)+f(n-1)
另外,使用return的尾递归还跟函数式编程有一点关系
编译器对尾递归的优化
上面说了,你光手动写成尾递归的形式,并没有什么卵用,要实现优化,还需要编译器中加入了对尾递归优化的机制
有了这个机制,编译的时候,就会自动利用上面的特点一来进行优化
具体是怎么优化的:
简单说就是重复利用同一个栈帧,不仅不用释放上一个,连下一个新的都不用开,效率非常高(有人做实验,这个比递推比迭代都要效率高)
为什么写成尾递归的形式,编译器就能优化了?或者说【编译器对尾递归的优化】的一些深层思想
说是深层思想,其实也是因为正好编译器其实在这里没做什么复杂的事,所以很简单
由于这两方面的原因,尾递归优化得以实现,而且效果很好
因为在递归调用自身的时候,这一层函数已经没有要做的事情了,虽然被递归调用的函数是在当前的函数里,但是他们之间的关系已经在传参的时候了断了,也就是这一层函数的所有变量什么的都不会再被用到了,所以当前函数虽然没有执行完,不能弹出栈,但它确实已经可以出栈了,这是一方面
另一方面,正因为调用的是自身,所以需要的存储空间是一毛一样的,那干脆重新刷新这些空间给下一层利用就好了,不用销毁再另开空间
有人对写成尾递归形式的说法是【为了告诉编译器这块要尾递归】,这种说法可能会导致误解,因为不是只告诉编译器就行,而是你需要做优化的前半部分,之后编译器做后半部分
所以总结:为了解决递归的开销大问题,使用尾递归优化,具体分两步:1)你把递归调用的形式写成尾递归的形式;2)编译器碰到尾递归,自动按照某种特定的方式进行优化编译
https://blog.csdn.net/yan_chou/article/details/59488871
斐波那契数列
常规的斐波那契数列算法可能是这样的:
1
2
3
4
5
6
7
|
int fib( int n) { if (n <= 2) { return 1; } return fib(n - 1) + fib(n - 2); } |
上面的这种递归计算最终的return操作是加法操作。所以不是尾递归。
如果用尾递归就是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/** 计算第n位斐波那契数列的值 @param n 第n个数 @param acc1 第n个数 @param acc2 第n与第n+1个数的和 @return 返回斐波那契数列值 */ int tailfib( int n, int acc1, int acc2) { if (n < 2) { return acc1; } return tailfib(n-1,acc2,acc1 + acc2); } |
比如我们想计算第10位斐波那契数列的值,只需要fib(10,1,1)即可。
看一下测试效果,测试程序如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
int main( int argc, const char * argv[]) { clock_t start,finish; start = clock(); printf( "计算结果:%d
" , fib(45)); finish = clock(); printf( "花费时间--------%lu
" ,finish - start); start = clock(); printf( "计算结果:%d
" , tailfib(45,1,1)); finish = clock(); printf( "花费时间--------%lu
" ,finish - start); return 0; } |
计算结果如下:
1
2
3
4
5
|
计算结果:1134903170 花费时间--------5540692 计算结果:1134903170 花费时间--------4 Program ended with exit code: 0 |
https://www.cnblogs.com/zhanggui/p/7722541.html
以上是关于尾递归优化的主要内容,如果未能解决你的问题,请参考以下文章