斐波那契数列的递归与非递归求解方法&递归的优缺点

        在C语言中,递归指的是函数在函数体内部调用了函数自身。这种形式对于解决一些能够用分治法将主问题分解成若干子问题,且子问题的结构与主问题相似的问题的时候,可以极大地简化程序的编写,但是递归的思想对于初学者来说一般都难以接受。其实递归函数的使用主要抓住两点,第一是主问题与子问题之间的拆分与组合关系,第二就是递归的结束条件,清楚这两个要素再来编写递归函数就会简单多了。

        但是递归函数也有一些隐含的缺点,这就要从函数调用本质说起了。首先从整体上看,函数调用是从一个正在执行的程序A跳转到另外一个程序B去执行,当执行完程序B后继续回到程序A中执行,这就要求CPU在从程序A跳转出去之前先将程序A的“现场”,在执行完B后再将A的“现场”恢复。这个保存和恢复现场的操作是通过程序堆栈来实现的。

函数的递归调用与普通的函数调用的区别是,递归调用的嵌套可能会很深,也就是说程序A调用程序A1,A1有调用A2,A2调用A3,........ 直到满足递归终止条件。这就带来了以下几个问题:

        1、在遇到递归终止条件之前不断地将程序现场压栈,可能会导致堆栈溢出。

         2、保存现场和恢复现场带来了额外的开销。

        3、可能会产生过多的冗余计算,浪费计算资源(比如递归实现斐波那契)。

下面通过一个例子来比较一下递归的利与弊:

        计算斐波那契数列: F(n)= F(n-1)+F(n-2)

一、递归实现:

long F(int n)

{

        if(n<=2)   return 1;

       return   F(n-1)+F(n-2);

}

从编程角度来说非常简洁,两行代码就完成了,而且理论上完全没问题。

但是:计算一下F(10),要前反复调用94次F(n),嵌套8层,最糟糕的是F(2)被重复计算了31次,F(3)被重复计算了21次,F(4)被重复计算了13次,.......而且这些重复的计算其计算过程和结果是完完全全一样的。可见计算的“性价比”是多么低。(当F(n)的n更大时,反复调用F(N)的次数,以及被重复计算的次数将接近于呈指数的增长,在计算F(30)时,在不考虑堆栈溢出的情况下,F(3)将被重复计算317811次,.........)。

二、非递归实现:

long F(int n )

{

 long result;

long pre_result;

long pre_pre_result;

result = pre_result = 1;

while(n>2){

n=n-1;

pre_pre_result = pre_result;

pre_result = result;

result = pre_result + pre_pre_result;

}

return result;

}

虽然在程序的实现上非递归的形式略微繁琐了一点,但是相对于递归形式实现来说,其效率提高了几十万倍不止!所以,递归有递归的好处,在一些特殊问题求解上会非常方便,但也有他的坏处,在资源有限的处理器上运行时,应谨慎使用!

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值