优化递归的效率zz

函数递归调用是很常见的做法,但是它往往是低效的,本文探讨优化递归效率的思路。

1.尾递归转换成迭代

尾递归是一种简单的递归,它可以用迭代来代替 比如 求阶乘函数的递归表达
优化递归的效率zzintf(intn)

优化递归的效率zz
{

优化递归的效率zz
if(n<=0)return1;

优化递归的效率zz
returnnf(n-1);

优化递归的效率zz}

可以转换成完全等价的循环迭代
优化递归的效率zzintf(intn)

优化递归的效率zz
{

优化递归的效率zz
intr=0;

优化递归的效率zz
while(n-->0)

优化递归的效率zz r
=n;

优化递归的效率zz
returnr;

优化递归的效率zz}

尾递归是最简单的情形,好的编译器甚至可以自动的识别尾递归并把它转换成循环迭代。

2.动态规划

我一直把动态规划看作尾递归的推广(个人观点),在2维或更高的情况下,直接使用递归会造成大量的重复计算,例如在斐波那契数列的递归关系 Fib(n+2)=Fib(n+1)+Fib(n)中 Fib(3)在计算Fib(4)和Fib(5)都会用到 他被重复计算了2遍,当数列长度增大时 这种浪费会变得越来越明显。

动态规划方法将可能需要的结果全部计算出来 并保存 一般来说 动态规划从最小数开始 自底向上计算所有值(因为后面的结果会用到前面的结果) 直到得到的结果中包含了要求的结果。
优化递归的效率zzintFib(unsigned n)

优化递归的效率zz
{

优化递归的效率zz
if(n==1)return1;

优化递归的效率zz
if(n==0)return0;

优化递归的效率zz
returnFib(n-1)+Fib(n-2);

优化递归的效率zz}


优化递归的效率zz

优化递归的效率zz

优化递归的效率zz
intFib(unsigned n)

优化递归的效率zz
{

优化递归的效率zz
int*f=newint[n+1];

优化递归的效率zz f[
1]=1;f[0]=0;

优化递归的效率zz
for(inti=0;i<=n;i++);

优化递归的效率zz f[i]
=f[i-1]+f[i-2];

优化递归的效率zz
intr=f[n];

优化递归的效率zz delete[] f;

优化递归的效率zz
returnr;

优化递归的效率zz}

动态规划不会造成重复运算 但是 它可能计算不需要的结果 例如关系式

a(n)=a(n-2)+a(n-4);

使用动态规划会计算很多不需要的结果,尽管如此,它的效率远远高于直接递归运算。

实际上,大部分时候动态规划把指数级时间复杂度的递归运算变成了多项式级时间复杂度的递推。

3.备忘录

减少重复值的另一个方法是使用备忘录,每次成功计算一个结果 ,就将它存入备忘录中,当再次遇到此问题时,无需重复计算,直接取出即可。

备忘录方法和直接递归相似,只是在函数在计算之前先访问备忘录,如果在备忘录中找到,就无须再计算,直接返回。

备忘录结构可以使用关联数组 哈希表等实现,特别地,当递归参数是整数时 直接用数组就可以了。

与动态规划相比,备忘录消耗了额外的备忘录查找时间,并且和直接递归一样 有大量的多余函数调用开销,但它不会造成额外计算。

4.内联

这是来自Efficient C++的方法,C++编译器不会把递归函数内联,这样,函数调用的开销变得很大。为了提高效率,必须手动内联函数。

递归函数无法完全内联,但是我们可以把它展开,这是前面Fibnacci函数的一层展开
优化递归的效率zzintFib(unsigned n)

优化递归的效率zz
{

优化递归的效率zz
if(n==1)return1;

优化递归的效率zz
if(n==0)return0;

优化递归的效率zz

优化递归的效率zz
intfn1,fn2;

优化递归的效率zz
if(n-1==1)fn1=1;

优化递归的效率zz
elseif(n-1==0)fn1=0;

优化递归的效率zz
elsefn1=Fib(n-2)+Fib(n-3);

优化递归的效率zz

优化递归的效率zz
if(n-2==1)fn2=1;

优化递归的效率zz
elseif(n-2==0)fn2=0;

优化递归的效率zz
elsefn2=Fib(n-3)+Fib(n-4);

优化递归的效率zz

优化递归的效率zz
returnfn1+fn2

优化递归的效率zz}

5.解递归

尽管我们倾向于虐待计算机 让它帮我们处理较复杂的问题,但是很多时候我们需要获得效率,就必须自己动手,其实很多递归式可以手动解出,组合数学为我们提供了不少工具:

(1)解齐次递归方程



简单的递归方程可以按以下步骤求解:
解Fibonacci函数的递归方程优化递归的效率zz首先把它转换成下面的式子优化递归的效率zz这个代数方程被称为递归方程的特征方程,下一步是解特征方程求出它的所有解,对这个例子来说优化递归的效率zz根据组合数学的结论优化递归的效率zz再由F(0)=0和F(1)=1可以得出方程组优化递归的效率zz解这个方程组可得到a和b的值优化递归的效率zz代入前面的公式可以求出Fibnacci通项公式优化递归的效率zz验证后可以知道,这个公式是正确的,显然用此公式做浮点运算,比使用递归方式快得多。(2)母函数组合数学中还提供了一种更强有力的处理手段:生成函数(又称为母函数)仍然以求解Fibonacci数列为例,为了易于理解,我这里把生成函数描述成一个以Fibonacci数列为系数的多项式。即优化递归的效率zz现在考虑这样一个多项式优化递归的效率zz按g(x)的定义,可以这样展开优化递归的效率zz优化递归的效率zz优化递归的效率zz这个时候不要忘记我们的递推公式,可以进一步化简为优化递归的效率zz这个式子与g(x)非常像,将它两边同时乘以x优化递归的效率zz优化递归的效率zz优化递归的效率zz再整理一下等式优化递归的效率zz利用F(0)=0,F(1)=1可以求出优化递归的效率zz这样 我们求出了g(x),等等,g(x)是什么来着?不是以Fibonacci数列为系数的多项式么?现在求出的东西是什么?不要急,用泰勒级数展开就能得到通项公式了,结果跟上面的是一样的。(太麻烦了,略过略过^_^)原文链接: https://www.cnblogs.com/end/archive/2011/09/15/2177805.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/32334

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月8日 上午9:34
下一篇 2023年2月8日 上午9:35

相关推荐