Fibonacci数列 递归和非递归的解法

来源:互联网 发布:编程入门用什么软件 编辑:程序博客网 时间:2024/05/09 12:30

Fibonacci数列,我想有的人在大学甚至高中就已经接触过了,其数学表达如下:
给定一正整数x,
F(x) = 1 ( x=1 或 x=2)
F(x) = F(x-1) + F(x-2) ( x > 2 )
也就是说,前2个数是1, 后面的的数, 是前面2个数之和

如果用计算机来解决的话, 可有递归和非递归算法, 对于递归算法很好理解, 也很好实现,直接照着上面的公式来就行了, 下面是递归算法的c语言实现:

long fab(int n)
    {
        if ( n == 1 || n == 2 )
            return 1;
        else
            return fab(n-1) + fab(n-2);
    }    


可以看见,代码非常的简单,也很好理解,然而, 这个效率是极其低下, 我试图打印前50个数, 结果发现程序运行了近2分钟才返回,打印的越多, 运行的越慢, 所耗费的时间成级数增长。有关这个递归算法的时间复杂度计算:

T(1) =  1
T(2) = 2

T(N) = T(N-1)+ T(N-2)

求解T(N)的过程会用到高数中的通项公式,我基本忘完了了。

不过我在《数据结构与算法分析-c语言描述》看到,可以使用归纳法推导出:(3/2)^n<T(N)<(5/3)^n

我搜索到网上的结果为(1.618)^n,说明这个是以某个指数级增长的。

参考网址:http://zhidao.baidu.com/question/63335536.html


下面是非递归算法,非递归的算法的思想其实也很简单:如果你要计算第N个数,只需要循环N次,每次用两个数来记录第N-1和N-2个数,因为第N个

数只是和它前面两个数有关系,和其他数据没有关系。

时间复杂度却是O(n)。而且同样打印前面50个数, 只用了1秒钟, 可见,这个差别是多么的巨大。 下面是非递归算法的c语言代码:

long fabx(int n)
    {
        if ( n == 1 || n == 2 )
            return 1;
        
        long xx = 1;
        long yy = 1;
        long res = 0;
        for ( int i = 0; i < n - 2 ; i++ )
        {
            res = xx + yy;
            xx = yy;
            yy = res;            
        }
        return res;
    }    

我觉得这个算法的时间复杂度已经不错了,当然还有一些其他更优秀的解法,矩阵方面的,

可以将时间复杂度降低为logN,我暂不考虑,因为数学很久不碰,很多东西都忘了。

总结几点结论:

1.递归的方法并非不好,之所以这个Fibonacci数列用递归方式计算,效率不高,是因为他

有重复的计算。计算第N个值时要计算第N-1,N-2个值,计算第N+1个值时,要计算第N,N-1

个值,每个值重复计算了。在其他很多情况下,使用递归,效率是很高的。

2.递归的代码清晰简洁,容易让人看懂,但是递归函数,递归的次数太多,会增加很多

堆栈的开销,增加空间复杂度。

3.算法的改良,主要在于思想的转变,多想想用什么方式可以做得更好。

4.时间复杂度的计算,矩阵算法,都必须把数学学好。