搜索
bottom↓
回复: 9

请教一下这个递归函数为什么运行得这么慢,是不是死循环了?

[复制链接]

出0入0汤圆

发表于 2010-3-30 16:56:27 | 显示全部楼层 |阅读模式
long fun2(int Num)
{
if(Num==0)return 0;
if(Num==1)return 1;

return (fun2(Num-2)+fun2(Num-1));
}


int main(int argc,char *argv[])
{
  printf("%lu  ",fun2(50));
}

当参数Num 大于40的时候运行就很慢,不知是什么问题。。

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2010-3-30 17:09:07 | 显示全部楼层
几何级增长的运算量。。。你可以计算器算一下,40!的运算量有多大。。。

出0入0汤圆

发表于 2010-3-30 17:20:00 | 显示全部楼层
他算的不是阶乘
你每递归一次,就相当于调用一次函数,这涉及到入栈和出栈操作,你可以算一下你的函数嵌套的层数

出0入0汤圆

发表于 2010-3-30 17:41:20 | 显示全部楼层
嗯,我弄错了,我当压栈次数成阶乘增长了。
n = 2时,调用次数=1+1+1=3
n = 3时,调用次数=3+1+1=5
n = 4时,调用次数=3+5+1=9
n = 5时,调用次数=5+9+1=15
n = 6时,调用次数=9+15+1=25
n = 7时,调用次数=15+25+1=41
n = 8时,调用次数=25+41+1=67
n = 40 时,fun2的调用次数LZ自己算吧

出0入0汤圆

 楼主| 发表于 2010-3-30 18:16:53 | 显示全部楼层
谢谢指点了,这是C语言二级考试的一条上机题。

出0入0汤圆

发表于 2010-3-30 20:20:41 | 显示全部楼层
我把这个递归函数用两种方法各写了一遍:

int func1(int n)
{
    if (n <= 1) return n;
    return func1(n - 1) + func1(n - 2);
}

__int64 func2(__int64 n, __int64 *a1 = NULL)
{
    if (n == 0) return 0;
    else if (n == 1)
    {
        if (a1) *a1 = 0;
        return 1;
    }
    else if (n == 2)
    {
        if (a1) *a1 = 1;
        return 1;
    }
    __int64 p, q;
    __int64 k = func2(n - 1, &p);
    if (a1) *a1 = k;
    return p + k;
}

然后调用:
    DWORD tick1 = GetTickCount();
    int w = func1(40);
    DWORD tick2 = GetTickCount();
    int x = func1(41);
    DWORD tick3 = GetTickCount();
    int y = func1(42);
    DWORD tick4 = GetTickCount();
    __int64 z = func2(50);
    DWORD tick5 = GetTickCount();

结果:
tick2 - tick1 = 11047
tick3 - tick2 = 17834
tick4 - tick3 = 28938
tick5 - tick4 = 0


再调用:
    DWORD tick4 = GetTickCount();
    __int64 z = func2(100);
    DWORD tick5 = GetTickCount();

结果:
tick5 - tick4 = 0

高效递归函数的关键,在于处理递归函数里面的历史计算结果。f(n)被多次调用,如果每次调用的结果都是相同的,那么就要把f(n)的值记录下来,这样就可以迅速的完成计算。
第一种方法之所以慢,是因为计算f(n),n加1,f(0)就要多调用62%那么多次,可见冗余的计算量是相当可观的。

出0入0汤圆

 楼主| 发表于 2010-3-31 00:40:31 | 显示全部楼层
LS 厉害,分析得很透彻!

原题要计算的N=1000,如果按原来的递归算法计算不知要计到猴年马月了~~

我分析一下这个函数的规律,使用了另一种算法,这样就很快捷了。

long fun(int Num)
{
  int s,n=2,pre1=1,pre2=1;

  
  if(n==Num)return 1;

  while(1)  //n>=3
  {
   s=pre1+pre2;
   pre2=pre1;
   pre1=s;
   if(++n>=Num)break;
  }

  return s;

}

出0入93汤圆

发表于 2010-3-31 12:50:50 | 显示全部楼层
这不是斐波那契数列吗,直接上通项公式呀!

出0入0汤圆

发表于 2010-3-31 13:02:17 | 显示全部楼层
斐波那契数列还要再加1,也不完全是斐波那契数列啊,算到40项随便写两行代码就出来了。。

出0入93汤圆

发表于 2010-4-1 10:34:51 | 显示全部楼层
回复【8楼】wwuchang  
斐波那契数列还要再加1,也不完全是斐波那契数列啊,算到40项随便写两行代码就出来了。。
-----------------------------------------------------------------------

变种,变种,从第1项(func(1))往后看就是斐波那契数列了,第0项直接赋值0就OK了。

【6楼】 dzqqqq
原题要计算的N=1000,如果按原来的递归算法计算不知要计到猴年马月了~~
所以迭代是很麻烦的,还是通项公式快~~~
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-20 20:51

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表