# 斐波那契数列

斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称“兔子数列”,其数值为:1、1、2、3、5、8、13、21、34……在数学上,这一数列以如下递推的方法定义:F(0)=1,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)。

# 下面用不同的方式实现一个函数,用来返回斐波那契数列的第N项

# 1、递归

    function fb1(n) {
        if( n ===1 || n === 2 ) return 1
        return fb1(n-1)+fb1(n-2)
    }
1
2
3
4

# 2、迭代 递推

    function fb2(n) {
        let cur = 1
        let next = 1
        if( n ===1 || n === 2 ) return next
        for(let i = 3;i<=n;i++) {
            [cur,next] = [next,cur+next] 
        }
        return next
    }
1
2
3
4
5
6
7
8
9

# 3、数组 动态规划

    function fb3(n){
        if( n ===1 || n === 2 ) return 1
        const num = [1,1]
        for(let i = 2; i < n; i++){
            num[i] =  num[i-1] + num[i-2]
        }
        return num.pop()
    }
1
2
3
4
5
6
7
8

# 4、尾递归(尾调用)

    function fb4(n,cur=1,next=1) {
        if( n ===1 || n === 2 ) return next
        return fb4(n-1,next,cur+next)
    }
1
2
3
4

# 通过代码执行时长,来看每种实现方式的性能

    console.time('fb1')
    console.log('*********1', fb1(40))
    console.timeEnd('fb1')
    console.time('fb2')
    console.log('*********2', fb2(40))
    console.timeEnd('fb2')
    console.time('fb3')
    console.log('*********3', fb3(40))
    console.timeEnd('fb3')
    console.time('fb4')
    console.log('*********4', fb4(40))
    console.timeEnd('fb4')
    控制台打印结果:
    *********1 102334155
    fb1: 1020.323974609375 ms
    *********2 102334155
    fb2: 0.13720703125 ms
    *********3 102334155
    fb3: 0.06201171875 ms
    *********4 102334155
    fb4: 0.15478515625 ms
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 由以上结果可以得出如下结论:

# 1、递归调用非常的消耗性能,并且当n非常大的时候,递归深度过大导致栈内存溢出,即“爆栈”

# 2、有相当多的重复计算

fb(7)
= fb(6) + fb(5) // 这里计算了f(5),下面又计算了一次f(5)
= (fb(5) + fb(4)) + (fb(4) + fb(3)) // 这里计算了两次f(5)
...

# 3、解决上面两个问题,采用尾递归。

尾调用:一个函数里的最后一个动作是返回一个函数的调用结果,即最后一步新调用的返回值被当前函数返回。
尾递归: 如果函数在尾调用位置调用自身。
尾递归是一种特殊的尾调用,即在尾部直接调用自身的递归函数。由于尾调用消除,使得尾递归只存在一个栈帧,所以永远不会“爆栈”。

Last Updated: 9/12/2023, 6:09:32 PM