8-1 计算第n个斐波那契数

斐波那契数(Fibonacci Number)

斐波那契数列(Fibonacci Sequence)是数学中最著名的数列之一,由意大利数学家比萨的莱昂纳多(Leonardo of Pisa),又名斐波那契(Fibonacci)在 1202 年的著作《计算之书》中提出。

数列的定义如下:

F(0) = 0
F(1) = 1
F(n) = F(n-1) + F(n-2)    (n >= 2)

数列的前几项为:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...

斐波那契数列在自然界和计算机科学中有着广泛的应用:

  • 黄金比例(Golden Ratio):相邻两项的比值趋近于黄金比例 φ ≈ 1.618
  • 自然界:向日葵的螺旋排列、贝壳的形状、松果的鳞片数
  • 算法分析:作为动态规划(Dynamic Programming)的经典入门问题
  • 数据结构:斐波那契堆(Fibonacci Heap)的名称来源

计算第 n 个斐波那契数有多种方法,从最朴素的递归到高效的矩阵快速幂,各有优劣。


递归法

递归法(Recursive Approach)是斐波那契数列定义的直接翻译:将 F(n) 表示为 F(n-1) + F(n-2),直到到达基准情形 F(0) = 0 和 F(1) = 1。

这种方法直观简洁,但存在严重的效率问题:计算 F(n) 时,F(n-1) 和 F(n-2) 各自会产生大量重复计算。以计算 F(5) 为例:

                    F(5)
                   /    \
               F(4)      F(3)
              /    \     /   \
          F(3)   F(2)  F(2)  F(1)
         /   \   / \   / \
      F(2) F(1) F(1)F(0) F(1)F(0)
      / \
   F(1) F(0)

可以看到 F(3) 被计算了 2 次,F(2) 被计算了 3 次。随着 n 的增大,重复计算的次数呈指数级增长,时间复杂度为 O(2^n)。

C++ 实现

#include <iostream>

int fibonacci(int n) 
{
    // base cases
    if (n == 0) return 0;
    if (n == 1) return 1;

    // recursive case
    return fibonacci(n - 1) + fibonacci(n - 2);
}

int main() 
{
    int n = 10;
    std::cout << "F(" << n << ") = " << fibonacci(n) << "\n";
    return 0;
}

运行该程序将输出

F(10) = 55

函数 fibonacci 直接按照数学定义递归求解。当 n 较小时非常直观,但 n 超过 40 后运行时间会明显变慢,因为存在大量重复计算。

C 实现

#include <stdio.h>

int fibonacci(int n) 
{
    // base cases
    if (n == 0) return 0;
    if (n == 1) return 1;

    // recursive case
    return fibonacci(n - 1) + fibonacci(n - 2);
}

int main() 
{
    int n = 10;
    printf("F(%d) = %d\n", n, fibonacci(n));
    return 0;
}

运行该程序将输出

F(10) = 55

C 语言版本的递归实现逻辑与 C++ 完全一致,仅输出方式不同。

Python 实现

def fibonacci(n):
    # base cases
    if n == 0:
        return 0
    if n == 1:
        return 1

    # recursive case
    return fibonacci(n - 1) + fibonacci(n - 2)

n = 10
print(f"F({n}) = {fibonacci(n)}")

运行该程序将输出

F(10) = 55

Python 的递归实现更加简洁,且整数没有溢出问题,但默认递归深度限制为 1000 层,可通过 sys.setrecursionlimit() 调整。

Go 实现

package main

import "fmt"

func fibonacci(n int) int {
    // base cases
    if n == 0 {
        return 0
    }
    if n == 1 {
        return 1
    }

    // recursive case
    return fibonacci(n-1) + fibonacci(n-2)
}

func main() {
    n := 10
    fmt.Printf("F(%d) = %d\n", n, fibonacci(n))
}

运行该程序将输出

F(10) = 55

Go 语言版本的递归逻辑与其他语言一致。注意 Go 的 if 语句条件不需要括号。


记忆化递归(Memoization)

记忆化递归(Memoization)是对朴素递归的优化:将已经计算过的结果存储起来,下次需要时直接查表,避免重复计算。这是一种自顶向下(Top-down)的动态规划方法。

核心思路:

  • 使用一个数组或哈希表作为"备忘录"(Memo),记录每个 F(i) 的结果。
  • 计算 F(n) 前,先查备忘录是否已有结果。
  • 如果有,直接返回;如果没有,递归计算后存入备忘录。

时间复杂度优化到 O(n),空间复杂度为 O(n)。

C++ 实现

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

long long memo[100];

long long fibonacci(int n) 
{
    // base cases
    if (n == 0) return 0;
    if (n == 1) return 1;

    // check memo: already computed
    if (memo[n] != -1) return memo[n];

    // compute and store in memo
    memo[n] = fibonacci(n - 1) + fibonacci(n - 2);
    return memo[n];
}

int main() 
{
    // initialize memo with -1 (not computed)
    memset(memo, -1, sizeof(memo));

    int n = 10;
    cout << "F(" << n << ") = " << fibonacci(n) << "\n";

    // test larger value
    memset(memo, -1, sizeof(memo));
    int m = 50;
    cout << "F(" << m << ") = " << fibonacci(m) << "\n";

    return 0;
}

运行该程序将输出

F(10) = 55
F(50) = 12586269025

使用 memo 数组存储已计算的结果。memset 将数组初始化为 -1 表示尚未计算。通过记忆化,F(50) 可以在瞬间计算完成,而朴素递归几乎无法在合理时间内完成。

C 实现

#include <stdio.h>
#include <string.h>

long long memo[100];

long long fibonacci(int n) 
{
    // base cases
    if (n == 0) return 0;
    if (n == 1) return 1;

    // check memo: already computed
    if (memo[n] != -1) return memo[n];

    // compute and store in memo
    memo[n] = fibonacci(n - 1) + fibonacci(n - 2);
    return memo[n];
}

int main() 
{
    // initialize memo with -1 (not computed)
    memset(memo, -1, sizeof(memo));

    int n = 10;
    printf("F(%d) = %lld\n", n, fibonacci(n));

    // test larger value
    memset(memo, -1, sizeof(memo));
    int m = 50;
    printf("F(%d) = %lld\n", m, fibonacci(m));

    return 0;
}

运行该程序将输出

F(10) = 55
F(50) = 12586269025

C 语言版本使用全局数组 memomemset 初始化,注意 F(50) 的结果超过 32 位整数范围,需使用 long long%lld 格式说明符。

Python 实现

def fibonacci(n, memo=None):
    if memo is None:
        memo = {}

    # base cases
    if n == 0:
        return 0
    if n == 1:
        return 1

    # check memo: already computed
    if n in memo:
        return memo[n]

    # compute and store in memo
    memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo)
    return memo[n]

n = 10
print(f"F({n}) = {fibonacci(n)}")

m = 50
print(f"F({m}) = {fibonacci(m)}")

运行该程序将输出

F(10) = 55
F(50) = 12586269025

Python 使用字典作为备忘录,通过 memo=None 避免默认参数的可变对象陷阱。Python 的整数自动支持任意精度,因此无需担心溢出。

Go 实现

package main

import "fmt"

func fibonacci(n int, memo map[int]int64) int64 {
    // base cases
    if n == 0 {
        return 0
    }
    if n == 1 {
        return 1
    }

    // check memo: already computed
    if val, ok := memo[n]; ok {
        return val
    }

    // compute and store in memo
    memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo)
    return memo[n]
}

func main() {
    n := 10
    fmt.Printf("F(%d) = %d\n", n, fibonacci(n, make(map[int]int64)))

    m := 50
    fmt.Printf("F(%d) = %d\n", m, fibonacci(m, make(map[int]int64)))
}

运行该程序将输出

F(10) = 55
F(50) = 12586269025

Go 语言使用 map[int]int64 作为备忘录,通过逗号 ok 模式(val, ok := memo[n])判断键是否存在。使用 int64 确保 64 位精度。


迭代法

迭代法(Iterative Approach)采用自底向上(Bottom-up)的策略:从已知的 F(0) 和 F(1) 出发,逐步向前计算,直到得到 F(n)。这是一种直观且高效的动态规划方法。

基本思路:

  • 创建数组 dp,其中 dp[0] = 0dp[1] = 1
  • 对 i 从 2 到 n,计算 dp[i] = dp[i-1] + dp[i-2]
  • 最终 dp[n] 即为所求。

时间复杂度 O(n),空间复杂度 O(n)。

C++ 实现

#include <iostream>
#include <vector>

using namespace std;

long long fibonacci(int n) 
{
    // base cases
    if (n == 0) return 0;
    if (n == 1) return 1;

    // dp array to store results
    vector<long long> dp(n + 1);
    dp[0] = 0;
    dp[1] = 1;

    // fill dp table bottom-up
    for (int i = 2; i <= n; i++) 
    {
        dp[i] = dp[i - 1] + dp[i - 2];
    }

    return dp[n];
}

int main() 
{
    int n = 10;
    cout << "F(" << n << ") = " << fibonacci(n) << "\n";
    return 0;
}

运行该程序将输出

F(10) = 55

使用 vector<long long> 作为 dp 数组,从 F(2) 开始依次填充,避免了递归带来的重复计算和栈开销。

C 实现

#include <stdio.h>
#include <stdlib.h>

long long fibonacci(int n) 
{
    // base cases
    if (n == 0) return 0;
    if (n == 1) return 1;

    // allocate dp array
    long long *dp = (long long *)malloc((n + 1) * sizeof(long long));
    dp[0] = 0;
    dp[1] = 1;

    // fill dp table bottom-up
    for (int i = 2; i <= n; i++) 
    {
        dp[i] = dp[i - 1] + dp[i - 2];
    }

    long long result = dp[n];
    free(dp);
    return result;
}

int main() 
{
    int n = 10;
    printf("F(%d) = %lld\n", n, fibonacci(n));
    return 0;
}

运行该程序将输出

F(10) = 55

C 语言使用 malloc 动态分配 dp 数组,使用后通过 free 释放内存,避免内存泄漏。

Python 实现

def fibonacci(n):
    # base cases
    if n == 0:
        return 0
    if n == 1:
        return 1

    # dp list to store results
    dp = [0] * (n + 1)
    dp[0] = 0
    dp[1] = 1

    # fill dp table bottom-up
    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]

    return dp[n]

n = 10
print(f"F({n}) = {fibonacci(n)}")

运行该程序将输出

F(10) = 55

Python 使用列表(list)存储中间结果,语法简洁明了。列表的乘法操作 [0] * (n + 1) 可快速创建指定长度的数组。

Go 实现

package main

import "fmt"

func fibonacci(n int) int64 {
    // base cases
    if n == 0 {
        return 0
    }
    if n == 1 {
        return 1
    }

    // dp slice to store results
    dp := make([]int64, n+1)
    dp[0] = 0
    dp[1] = 1

    // fill dp table bottom-up
    for i := 2; i <= n; i++ {
        dp[i] = dp[i-1] + dp[i-2]
    }

    return dp[n]
}

func main() {
    n := 10
    fmt.Printf("F(%d) = %d\n", n, fibonacci(n))
}

运行该程序将输出

F(10) = 55

Go 语言使用切片(slice)make([]int64, n+1) 创建 dp 数组,语法清晰且自动管理内存。


空间优化迭代法

在迭代法中,我们实际上只需要前两个值就能计算当前值,整个 dp 数组并不是必需的。空间优化迭代法只维护两个变量来存储 F(n-1) 和 F(n-2),将空间复杂度从 O(n) 降低到 O(1)。

基本思路:

  • 用变量 prev2 表示 F(n-2),prev1 表示 F(n-1)。
  • 每次迭代计算 current = prev1 + prev2,然后更新 prev2 = prev1prev1 = current
  • 最终 prev1 即为 F(n)。

时间复杂度 O(n),空间复杂度 O(1)。

C++ 实现

#include <iostream>

using namespace std;

long long fibonacci(int n) 
{
    // base cases
    if (n == 0) return 0;
    if (n == 1) return 1;

    // only keep previous two values
    long long prev2 = 0;  // F(n-2)
    long long prev1 = 1;  // F(n-1)

    for (int i = 2; i <= n; i++) 
    {
        long long current = prev1 + prev2;
        prev2 = prev1;
        prev1 = current;
    }

    return prev1;
}

int main() 
{
    int n = 10;
    cout << "F(" << n << ") = " << fibonacci(n) << "\n";
    return 0;
}

运行该程序将输出

F(10) = 55

仅需两个变量 prev2prev1 即可完成计算,不需要任何额外数组,空间效率最优。

C 实现

#include <stdio.h>

long long fibonacci(int n) 
{
    // base cases
    if (n == 0) return 0;
    if (n == 1) return 1;

    // only keep previous two values
    long long prev2 = 0;  // F(n-2)
    long long prev1 = 1;  // F(n-1)

    for (int i = 2; i <= n; i++) 
    {
        long long current = prev1 + prev2;
        prev2 = prev1;
        prev1 = current;
    }

    return prev1;
}

int main() 
{
    int n = 10;
    printf("F(%d) = %lld\n", n, fibonacci(n));
    return 0;
}

运行该程序将输出

F(10) = 55

C 语言版本的实现与 C++ 完全一致,仅输出函数不同。这是实际工程中最常用的斐波那契计算方法。

Python 实现

def fibonacci(n):
    # base cases
    if n == 0:
        return 0
    if n == 1:
        return 1

    # only keep previous two values
    prev2 = 0  # F(n-2)
    prev1 = 1  # F(n-1)

    for i in range(2, n + 1):
        current = prev1 + prev2
        prev2 = prev1
        prev1 = current

    return prev1

n = 10
print(f"F({n}) = {fibonacci(n)}")

运行该程序将输出

F(10) = 55

Python 版本同样仅需两个变量,简洁高效。也可以使用 Python 的多元赋值进一步简化为 prev1, prev2 = prev1 + prev2, prev1

Go 实现

package main

import "fmt"

func fibonacci(n int) int64 {
    // base cases
    if n == 0 {
        return 0
    }
    if n == 1 {
        return 1
    }

    // only keep previous two values
    var prev2 int64 = 0 // F(n-2)
    var prev1 int64 = 1 // F(n-1)

    for i := 2; i <= n; i++ {
        current := prev1 + prev2
        prev2 = prev1
        prev1 = current
    }

    return prev1
}

func main() {
    n := 10
    fmt.Printf("F(%d) = %d\n", n, fibonacci(n))
}

运行该程序将输出

F(10) = 55

Go 语言版本使用显式类型声明 var prev2 int64 = 0 确保使用 64 位整数,逻辑与其他语言完全一致。


矩阵快速幂法

矩阵快速幂法(Matrix Exponentiation)利用了斐波那契数列的矩阵表示性质,可以在 O(log n) 时间内计算出 F(n)。

数学原理:斐波那契数列可以表示为矩阵乘法:

| F(n+1)  F(n)   |   | 1  1 | ^ n
| F(n)    F(n-1) | = | 1  0 |

即:

| F(n+1) |   | 1  1 | ^ n   | 1 |
| F(n)   | = | 1  0 |     * | 0 |

计算矩阵的 n 次幂时,使用快速幂(Exponentiation by Squaring)算法:

若 n 为偶数: M^n = (M^(n/2))^2
若 n 为奇数: M^n = M * M^(n-1)

这样将 O(n) 的逐次乘法降为 O(log n) 的分治计算。

时间复杂度 O(log n),空间复杂度 O(log n)(递归栈)或 O(1)(迭代版本)。

C++ 实现

#include <iostream>

using namespace std;

// 2x2 matrix multiplication
void multiply(long long a[2][2], long long b[2][2]) 
{
    long long x = a[0][0] * b[0][0] + a[0][1] * b[1][0];
    long long y = a[0][0] * b[0][1] + a[0][1] * b[1][1];
    long long z = a[1][0] * b[0][0] + a[1][1] * b[1][0];
    long long w = a[1][0] * b[0][1] + a[1][1] * b[1][1];

    a[0][0] = x;
    a[0][1] = y;
    a[1][0] = z;
    a[1][1] = w;
}

// matrix exponentiation by squaring
void power(long long mat[2][2], int n) 
{
    if (n == 0 || n == 1) return;

    long long base[2][2] = {{1, 1}, {1, 0}};

    power(mat, n / 2);
    multiply(mat, mat);

    // if n is odd, multiply by base matrix
    if (n % 2 != 0) 
    {
        multiply(mat, base);
    }
}

long long fibonacci(int n) 
{
    if (n == 0) return 0;

    long long mat[2][2] = {{1, 1}, {1, 0}};
    power(mat, n - 1);
    return mat[0][0];
}

int main() 
{
    int n = 10;
    cout << "F(" << n << ") = " << fibonacci(n) << "\n";
    return 0;
}

运行该程序将输出

F(10) = 55

power 函数通过递归将矩阵幂运算分解为子问题:先计算 M^(n/2),再自乘得到 M^n。奇数时额外乘一次基础矩阵。这使得计算 F(n) 的时间从 O(n) 降到 O(log n)。

C 实现

#include <stdio.h>

// 2x2 matrix multiplication
void multiply(long long a[2][2], long long b[2][2]) 
{
    long long x = a[0][0] * b[0][0] + a[0][1] * b[1][0];
    long long y = a[0][0] * b[0][1] + a[0][1] * b[1][1];
    long long z = a[1][0] * b[0][0] + a[1][1] * b[1][0];
    long long w = a[1][0] * b[0][1] + a[1][1] * b[1][1];

    a[0][0] = x;
    a[0][1] = y;
    a[1][0] = z;
    a[1][1] = w;
}

// matrix exponentiation by squaring
void power(long long mat[2][2], int n) 
{
    if (n == 0 || n == 1) return;

    long long base[2][2] = {{1, 1}, {1, 0}};

    power(mat, n / 2);
    multiply(mat, mat);

    // if n is odd, multiply by base matrix
    if (n % 2 != 0) 
    {
        multiply(mat, base);
    }
}

long long fibonacci(int n) 
{
    if (n == 0) return 0;

    long long mat[2][2] = {{1, 1}, {1, 0}};
    power(mat, n - 1);
    return mat[0][0];
}

int main() 
{
    int n = 10;
    printf("F(%d) = %lld\n", n, fibonacci(n));
    return 0;
}

运行该程序将输出

F(10) = 55

C 语言版本的矩阵快速幂与 C++ 逻辑完全一致,使用二维数组表示矩阵,通过指针传递实现原地修改。

Python 实现

def multiply(a, b):
    """2x2 matrix multiplication"""
    return [
        [a[0][0] * b[0][0] + a[0][1] * b[1][0],
         a[0][0] * b[0][1] + a[0][1] * b[1][1]],
        [a[1][0] * b[0][0] + a[1][1] * b[1][0],
         a[1][0] * b[0][1] + a[1][1] * b[1][1]]
    ]

def power(mat, n):
    """matrix exponentiation by squaring"""
    if n == 0 or n == 1:
        return mat

    base = [[1, 1], [1, 0]]

    # recursive squaring
    mat = power(mat, n // 2)
    mat = multiply(mat, mat)

    # if n is odd, multiply by base matrix
    if n % 2 != 0:
        mat = multiply(mat, base)

    return mat

def fibonacci(n):
    if n == 0:
        return 0

    mat = [[1, 1], [1, 0]]
    result = power(mat, n - 1)
    return result[0][0]

n = 10
print(f"F({n}) = {fibonacci(n)}")

运行该程序将输出

F(10) = 55

Python 版本使用嵌套列表表示矩阵,multiply 函数返回新矩阵而非原地修改,函数式风格更加清晰。

Go 实现

package main

import "fmt"

// 2x2 matrix type
type Matrix [2][2]int64

// 2x2 matrix multiplication
func multiply(a, b Matrix) Matrix {
	return Matrix{
		{a[0][0]*b[0][0] + a[0][1]*b[1][0], a[0][0]*b[0][1] + a[0][1]*b[1][1]},
		{a[1][0]*b[0][0] + a[1][1]*b[1][0], a[1][0]*b[0][1] + a[1][1]*b[1][1]},
	}
}

// matrix exponentiation by squaring
func power(mat Matrix, n int) Matrix {
	if n == 0 || n == 1 {
		return mat
	}

	base := Matrix{{1, 1}, {1, 0}}

	// recursive squaring
	mat = power(mat, n/2)
	mat = multiply(mat, mat)

	// if n is odd, multiply by base matrix
	if n%2 != 0 {
		mat = multiply(mat, base)
	}

	return mat
}

func fibonacci(n int) int64 {
	if n == 0 {
		return 0
	}

	mat := Matrix{{1, 1}, {1, 0}}
	result := power(mat, n-1)
	return result[0][0]
}

func main() {
	n := 10
	fmt.Printf("F(%d) = %d\n", n, fibonacci(n))
}

运行该程序将输出

F(10) = 55

Go 语言版本定义了 Matrix 类型 [2][2]int64multiply 函数返回新矩阵,代码结构清晰。Go 的类型系统使矩阵操作更加类型安全。


通项公式法(Binet's Formula)

斐波那契数列存在一个封闭形式的解析解,称为比奈公式(Binet's Formula):

F(n) = (φ^n - ψ^n) / √5

其中:

φ = (1 + √5) / 2 ≈ 1.6180339887...    (黄金比例,Golden Ratio)
ψ = (1 - √5) / 2 ≈ -0.6180339887...   (共轭黄金比例)

由于 |ψ| < 1,当 n 较大时 ψ^n 趋近于 0,因此 F(n) 实际上就是 φ^n / √5 四舍五入到最接近的整数。

该方法的时间复杂度为 O(1),但由于浮点数精度限制,当 n 较大时(通常 n > 70)会出现计算误差,因此仅适用于小规模计算或理论推导。

C++ 实现

#include <iostream>
#include <cmath>

using namespace std;

long long fibonacci(int n) 
{
    double sqrt5 = sqrt(5.0);
    double phi = (1.0 + sqrt5) / 2.0;    // golden ratio
    double psi = (1.0 - sqrt5) / 2.0;    // conjugate

    double result = (pow(phi, n) - pow(psi, n)) / sqrt5;
    return (long long)round(result);
}

int main() 
{
    int n = 10;
    cout << "F(" << n << ") = " << fibonacci(n) << "\n";
    return 0;
}

运行该程序将输出

F(10) = 55

使用 <cmath> 中的 sqrtpowround 函数计算比奈公式。round 确保浮点计算结果正确取整。

C 实现

#include <stdio.h>
#include <math.h>

long long fibonacci(int n) 
{
    double sqrt5 = sqrt(5.0);
    double phi = (1.0 + sqrt5) / 2.0;    // golden ratio
    double psi = (1.0 - sqrt5) / 2.0;    // conjugate

    double result = (pow(phi, n) - pow(psi, n)) / sqrt5;
    return (long long)round(result);
}

int main() 
{
    int n = 10;
    printf("F(%d) = %lld\n", n, fibonacci(n));
    return 0;
}

运行该程序将输出

F(10) = 55

C 语言版本使用 <math.h> 提供的数学函数,编译时需链接数学库(-lm)。

Python 实现

import math

def fibonacci(n):
    sqrt5 = math.sqrt(5)
    phi = (1 + sqrt5) / 2    # golden ratio
    psi = (1 - sqrt5) / 2    # conjugate

    result = (phi ** n - psi ** n) / sqrt5
    return round(result)

n = 10
print(f"F({n}) = {fibonacci(n)}")

运行该程序将输出

F(10) = 55

Python 版本使用 math.sqrt 和幂运算符 ** 实现比奈公式,round 函数确保正确取整。

Go 实现

package main

import (
	"fmt"
	"math"
)

func fibonacci(n int) int64 {
	sqrt5 := math.Sqrt(5)
	phi := (1 + sqrt5) / 2    // golden ratio
	psi := (1 - sqrt5) / 2    // conjugate

	result := (math.Pow(phi, float64(n)) - math.Pow(psi, float64(n))) / sqrt5
	return int64(math.Round(result))
}

func main() {
	n := 10
	fmt.Printf("F(%d) = %d\n", n, fibonacci(n))
}

运行该程序将输出

F(10) = 55

Go 语言版本使用 math 包中的函数,注意需要将 n 转换为 float64 类型以进行浮点运算。


完整对比

以下程序实现了所有方法,并对比它们在相同输入下的结果。通过对比不同方法的输出和耗时,可以直观地理解各方法的性能差异。

C++ 实现

#include <iostream>
#include <vector>
#include <cstring>
#include <cmath>
#include <chrono>

using namespace std;
using namespace std::chrono;

// Method 1: Simple Recursion
long long fib_recursive(int n) 
{
    if (n == 0) return 0;
    if (n == 1) return 1;
    return fib_recursive(n - 1) + fib_recursive(n - 2);
}

// Method 2: Memoization
long long fib_memo(int n, long long memo[]) 
{
    if (n == 0) return 0;
    if (n == 1) return 1;
    if (memo[n] != -1) return memo[n];
    memo[n] = fib_memo(n - 1, memo) + fib_memo(n - 2, memo);
    return memo[n];
}

// Method 3: Iterative with array
long long fib_iterative(int n) 
{
    if (n == 0) return 0;
    if (n == 1) return 1;
    vector<long long> dp(n + 1);
    dp[0] = 0;
    dp[1] = 1;
    for (int i = 2; i <= n; i++) 
    {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
}

// Method 4: Space-optimized iterative
long long fib_optimized(int n) 
{
    if (n == 0) return 0;
    if (n == 1) return 1;
    long long prev2 = 0, prev1 = 1;
    for (int i = 2; i <= n; i++) 
    {
        long long curr = prev1 + prev2;
        prev2 = prev1;
        prev1 = curr;
    }
    return prev1;
}

// Method 5: Matrix exponentiation
void mat_multiply(long long a[2][2], long long b[2][2]) 
{
    long long x = a[0][0] * b[0][0] + a[0][1] * b[1][0];
    long long y = a[0][0] * b[0][1] + a[0][1] * b[1][1];
    long long z = a[1][0] * b[0][0] + a[1][1] * b[1][0];
    long long w = a[1][0] * b[0][1] + a[1][1] * b[1][1];
    a[0][0] = x; a[0][1] = y; a[1][0] = z; a[1][1] = w;
}

void mat_power(long long mat[2][2], int n) 
{
    if (n == 0 || n == 1) return;
    long long base[2][2] = {{1, 1}, {1, 0}};
    mat_power(mat, n / 2);
    mat_multiply(mat, mat);
    if (n % 2 != 0) mat_multiply(mat, base);
}

long long fib_matrix(int n) 
{
    if (n == 0) return 0;
    long long mat[2][2] = {{1, 1}, {1, 0}};
    mat_power(mat, n - 1);
    return mat[0][0];
}

// Method 6: Binet's formula
long long fib_binet(int n) 
{
    double sqrt5 = sqrt(5.0);
    double phi = (1.0 + sqrt5) / 2.0;
    double psi = (1.0 - sqrt5) / 2.0;
    return (long long)round((pow(phi, n) - pow(psi, n)) / sqrt5);
}

int main() 
{
    int test_cases[] = {0, 1, 10, 20};
    long long memo[100];

    cout << "=== Fibonacci Comparison ===" << "\n\n";

    for (int n : test_cases) 
    {
        cout << "F(" << n << "):" << "\n";

        auto start = high_resolution_clock::now();
        cout << "  Recursive:        " << fib_recursive(n);
        auto end = high_resolution_clock::now();
        cout << "  (" << duration_cast<microseconds>(end - start).count() << " us)" << "\n";

        memset(memo, -1, sizeof(memo));
        start = high_resolution_clock::now();
        cout << "  Memoization:      " << fib_memo(n, memo);
        end = high_resolution_clock::now();
        cout << "  (" << duration_cast<microseconds>(end - start).count() << " us)" << "\n";

        start = high_resolution_clock::now();
        cout << "  Iterative:        " << fib_iterative(n);
        end = high_resolution_clock::now();
        cout << "  (" << duration_cast<microseconds>(end - start).count() << " us)" << "\n";

        start = high_resolution_clock::now();
        cout << "  Space-optimized:  " << fib_optimized(n);
        end = high_resolution_clock::now();
        cout << "  (" << duration_cast<microseconds>(end - start).count() << " us)" << "\n";

        start = high_resolution_clock::now();
        cout << "  Matrix:           " << fib_matrix(n);
        end = high_resolution_clock::now();
        cout << "  (" << duration_cast<microseconds>(end - start).count() << " us)" << "\n";

        start = high_resolution_clock::now();
        cout << "  Binet:            " << fib_binet(n);
        end = high_resolution_clock::now();
        cout << "  (" << duration_cast<microseconds>(end - start).count() << " us)" << "\n";

        cout << "\n";
    }

    return 0;
}

运行该程序将输出

=== Fibonacci Comparison ===

F(0):
  Recursive:        0  (0 us)
  Memoization:      0  (0 us)
  Iterative:        0  (0 us)
  Space-optimized:  0  (0 us)
  Matrix:           0  (0 us)
  Binet:            0  (0 us)

F(1):
  Recursive:        1  (0 us)
  Memoization:      1  (0 us)
  Iterative:        1  (0 us)
  Space-optimized:  1  (0 us)
  Matrix:           1  (0 us)
  Binet:            1  (0 us)

F(10):
  Recursive:        55  (5 us)
  Memoization:      55  (2 us)
  Iterative:        55  (1 us)
  Space-optimized:  55  (0 us)
  Matrix:           55  (3 us)
  Binet:            55  (1 us)

F(20):
  Recursive:        6765  (520 us)
  Memoization:      6765  (3 us)
  Iterative:        6765  (1 us)
  Space-optimized:  6765  (0 us)
  Matrix:           6765  (4 us)
  Binet:            6765  (1 us)

可以看到所有方法在相同的 n 值下结果一致。递归法的耗时随 n 增大而急剧增长,而其他方法保持高效。

C 实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

// Method 1: Simple Recursion
long long fib_recursive(int n) 
{
    if (n == 0) return 0;
    if (n == 1) return 1;
    return fib_recursive(n - 1) + fib_recursive(n - 2);
}

// Method 2: Memoization
long long fib_memo(int n, long long memo[]) 
{
    if (n == 0) return 0;
    if (n == 1) return 1;
    if (memo[n] != -1) return memo[n];
    memo[n] = fib_memo(n - 1, memo) + fib_memo(n - 2, memo);
    return memo[n];
}

// Method 3: Iterative with array
long long fib_iterative(int n) 
{
    if (n == 0) return 0;
    if (n == 1) return 1;
    long long *dp = (long long *)malloc((n + 1) * sizeof(long long));
    dp[0] = 0;
    dp[1] = 1;
    for (int i = 2; i <= n; i++) 
    {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    long long result = dp[n];
    free(dp);
    return result;
}

// Method 4: Space-optimized iterative
long long fib_optimized(int n) 
{
    if (n == 0) return 0;
    if (n == 1) return 1;
    long long prev2 = 0, prev1 = 1;
    for (int i = 2; i <= n; i++) 
    {
        long long curr = prev1 + prev2;
        prev2 = prev1;
        prev1 = curr;
    }
    return prev1;
}

// Method 5: Matrix exponentiation
void mat_multiply(long long a[2][2], long long b[2][2]) 
{
    long long x = a[0][0] * b[0][0] + a[0][1] * b[1][0];
    long long y = a[0][0] * b[0][1] + a[0][1] * b[1][1];
    long long z = a[1][0] * b[0][0] + a[1][1] * b[1][0];
    long long w = a[1][0] * b[0][1] + a[1][1] * b[1][1];
    a[0][0] = x; a[0][1] = y; a[1][0] = z; a[1][1] = w;
}

void mat_power(long long mat[2][2], int n) 
{
    if (n == 0 || n == 1) return;
    long long base[2][2] = {{1, 1}, {1, 0}};
    mat_power(mat, n / 2);
    mat_multiply(mat, mat);
    if (n % 2 != 0) mat_multiply(mat, base);
}

long long fib_matrix(int n) 
{
    if (n == 0) return 0;
    long long mat[2][2] = {{1, 1}, {1, 0}};
    mat_power(mat, n - 1);
    return mat[0][0];
}

// Method 6: Binet's formula
long long fib_binet(int n) 
{
    double sqrt5 = sqrt(5.0);
    double phi = (1.0 + sqrt5) / 2.0;
    double psi = (1.0 - sqrt5) / 2.0;
    return (long long)round((pow(phi, n) - pow(psi, n)) / sqrt5);
}

// timing helper
double time_us(clock_t start, clock_t end) 
{
    return ((double)(end - start)) / CLOCKS_PER_SEC * 1000000.0;
}

int main() 
{
    int test_cases[] = {0, 1, 10, 20};
    int num_cases = sizeof(test_cases) / sizeof(test_cases[0]);
    long long memo[100];

    printf("=== Fibonacci Comparison ===\n\n");

    for (int c = 0; c < num_cases; c++) 
    {
        int n = test_cases[c];
        printf("F(%d):\n", n);

        clock_t start, end;

        start = clock();
        printf("  Recursive:        %lld", fib_recursive(n));
        end = clock();
        printf("  (%.0f us)\n", time_us(start, end));

        memset(memo, -1, sizeof(memo));
        start = clock();
        printf("  Memoization:      %lld", fib_memo(n, memo));
        end = clock();
        printf("  (%.0f us)\n", time_us(start, end));

        start = clock();
        printf("  Iterative:        %lld", fib_iterative(n));
        end = clock();
        printf("  (%.0f us)\n", time_us(start, end));

        start = clock();
        printf("  Space-optimized:  %lld", fib_optimized(n));
        end = clock();
        printf("  (%.0f us)\n", time_us(start, end));

        start = clock();
        printf("  Matrix:           %lld", fib_matrix(n));
        end = clock();
        printf("  (%.0f us)\n", time_us(start, end));

        start = clock();
        printf("  Binet:            %lld", fib_binet(n));
        end = clock();
        printf("  (%.0f us)\n", time_us(start, end));

        printf("\n");
    }

    return 0;
}

运行该程序将输出

=== Fibonacci Comparison ===

F(0):
  Recursive:        0  (0 us)
  Memoization:      0  (0 us)
  Iterative:        0  (0 us)
  Space-optimized:  0  (0 us)
  Matrix:           0  (0 us)
  Binet:            0  (0 us)

F(1):
  Recursive:        1  (0 us)
  Memoization:      1  (0 us)
  Iterative:        1  (0 us)
  Space-optimized:  1  (0 us)
  Matrix:           1  (0 us)
  Binet:            1  (0 us)

F(10):
  Recursive:        55  (5 us)
  Memoization:      55  (2 us)
  Iterative:        55  (1 us)
  Space-optimized:  55  (0 us)
  Matrix:           55  (3 us)
  Binet:            55  (1 us)

F(20):
  Recursive:        6765  (520 us)
  Memoization:      6765  (3 us)
  Iterative:        6765  (1 us)
  Space-optimized:  6765  (0 us)
  Matrix:           6765  (4 us)
  Binet:            6765  (1 us)

C 语言版本使用 clock() 进行计时,编译时需添加 -lm 链接数学库。

Python 实现

import math
import time

# Method 1: Simple Recursion
def fib_recursive(n):
    if n == 0: return 0
    if n == 1: return 1
    return fib_recursive(n - 1) + fib_recursive(n - 2)

# Method 2: Memoization
def fib_memo(n, memo=None):
    if memo is None:
        memo = {}
    if n == 0: return 0
    if n == 1: return 1
    if n in memo: return memo[n]
    memo[n] = fib_memo(n - 1, memo) + fib_memo(n - 2, memo)
    return memo[n]

# Method 3: Iterative with array
def fib_iterative(n):
    if n == 0: return 0
    if n == 1: return 1
    dp = [0] * (n + 1)
    dp[0] = 0
    dp[1] = 1
    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]
    return dp[n]

# Method 4: Space-optimized iterative
def fib_optimized(n):
    if n == 0: return 0
    if n == 1: return 1
    prev2, prev1 = 0, 1
    for i in range(2, n + 1):
        prev2, prev1 = prev1, prev1 + prev2
    return prev1

# Method 5: Matrix exponentiation
def mat_multiply(a, b):
    return [
        [a[0][0]*b[0][0] + a[0][1]*b[1][0], a[0][0]*b[0][1] + a[0][1]*b[1][1]],
        [a[1][0]*b[0][0] + a[1][1]*b[1][0], a[1][0]*b[0][1] + a[1][1]*b[1][1]]
    ]

def mat_power(mat, n):
    if n == 0 or n == 1:
        return mat
    base = [[1, 1], [1, 0]]
    mat = mat_power(mat, n // 2)
    mat = mat_multiply(mat, mat)
    if n % 2 != 0:
        mat = mat_multiply(mat, base)
    return mat

def fib_matrix(n):
    if n == 0: return 0
    result = mat_power([[1, 1], [1, 0]], n - 1)
    return result[0][0]

# Method 6: Binet's formula
def fib_binet(n):
    sqrt5 = math.sqrt(5)
    phi = (1 + sqrt5) / 2
    psi = (1 - sqrt5) / 2
    return round((phi ** n - psi ** n) / sqrt5)

def time_us(func, *args):
    start = time.perf_counter()
    result = func(*args)
    end = time.perf_counter()
    return result, (end - start) * 1_000_000

test_cases = [0, 1, 10, 20]

print("=== Fibonacci Comparison ===\n")

for n in test_cases:
    print(f"F({n}):")

    result, t = time_us(fib_recursive, n)
    print(f"  Recursive:        {result}  ({t:.0f} us)")

    result, t = time_us(fib_memo, n)
    print(f"  Memoization:      {result}  ({t:.0f} us)")

    result, t = time_us(fib_iterative, n)
    print(f"  Iterative:        {result}  ({t:.0f} us)")

    result, t = time_us(fib_optimized, n)
    print(f"  Space-optimized:  {result}  ({t:.0f} us)")

    result, t = time_us(fib_matrix, n)
    print(f"  Matrix:           {result}  ({t:.0f} us)")

    result, t = time_us(fib_binet, n)
    print(f"  Binet:            {result}  ({t:.0f} us)")

    print()

运行该程序将输出

=== Fibonacci Comparison ===

F(0):
  Recursive:        0  (0 us)
  Memoization:      0  (0 us)
  Iterative:        0  (0 us)
  Space-optimized:  0  (0 us)
  Matrix:           0  (0 us)
  Binet:            0  (0 us)

F(1):
  Recursive:        1  (0 us)
  Memoization:      1  (0 us)
  Iterative:        1  (0 us)
  Space-optimized:  1  (0 us)
  Matrix:           1  (1 us)
  Binet:            1  (0 us)

F(10):
  Recursive:        55  (12 us)
  Memoization:      55  (7 us)
  Iterative:        55  (3 us)
  Space-optimized:  55  (1 us)
  Matrix:           55  (8 us)
  Binet:            55  (2 us)

F(20):
  Recursive:        6765  (1100 us)
  Memoization:      6765  (9 us)
  Iterative:        6765  (3 us)
  Space-optimized:  6765  (2 us)
  Matrix:           6765  (10 us)
  Binet:            6765  (2 us)

Python 版本使用 time.perf_counter() 进行高精度计时。由于 Python 解释器的开销,各方法的绝对耗时比 C/C++ 高,但相对趋势一致。

Go 实现

package main

import (
	"fmt"
	"math"
	"time"
)

// Method 1: Simple Recursion
func fibRecursive(n int) int64 {
	if n == 0 {
		return 0
	}
	if n == 1 {
		return 1
	}
	return fibRecursive(n-1) + fibRecursive(n-2)
}

// Method 2: Memoization
func fibMemo(n int, memo map[int]int64) int64 {
	if n == 0 {
		return 0
	}
	if n == 1 {
		return 1
	}
	if val, ok := memo[n]; ok {
		return val
	}
	memo[n] = fibMemo(n-1, memo) + fibMemo(n-2, memo)
	return memo[n]
}

// Method 3: Iterative with array
func fibIterative(n int) int64 {
	if n == 0 {
		return 0
	}
	if n == 1 {
		return 1
	}
	dp := make([]int64, n+1)
	dp[0] = 0
	dp[1] = 1
	for i := 2; i <= n; i++ {
		dp[i] = dp[i-1] + dp[i-2]
	}
	return dp[n]
}

// Method 4: Space-optimized iterative
func fibOptimized(n int) int64 {
	if n == 0 {
		return 0
	}
	if n == 1 {
		return 1
	}
	var prev2 int64 = 0
	var prev1 int64 = 1
	for i := 2; i <= n; i++ {
		prev2, prev1 = prev1, prev1+prev2
	}
	return prev1
}

// Method 5: Matrix exponentiation
type Matrix [2][2]int64

func matMultiply(a, b Matrix) Matrix {
	return Matrix{
		{a[0][0]*b[0][0] + a[0][1]*b[1][0], a[0][0]*b[0][1] + a[0][1]*b[1][1]},
		{a[1][0]*b[0][0] + a[1][1]*b[1][0], a[1][0]*b[0][1] + a[1][1]*b[1][1]},
	}
}

func matPower(mat Matrix, n int) Matrix {
	if n == 0 || n == 1 {
		return mat
	}
	base := Matrix{{1, 1}, {1, 0}}
	mat = matPower(mat, n/2)
	mat = matMultiply(mat, mat)
	if n%2 != 0 {
		mat = matMultiply(mat, base)
	}
	return mat
}

func fibMatrix(n int) int64 {
	if n == 0 {
		return 0
	}
	result := matPower(Matrix{{1, 1}, {1, 0}}, n-1)
	return result[0][0]
}

// Method 6: Binet's formula
func fibBinet(n int) int64 {
	sqrt5 := math.Sqrt(5)
	phi := (1 + sqrt5) / 2
	psi := (1 - sqrt5) / 2
	return int64(math.Round((math.Pow(phi, float64(n)) - math.Pow(psi, float64(n))) / sqrt5))
}

func timeExec(fn func() int64) (int64, time.Duration) {
	start := time.Now()
	result := fn()
	return result, time.Since(start)
}

func main() {
	testCases := []int{0, 1, 10, 20}

	fmt.Println("=== Fibonacci Comparison ===")
	fmt.Println()

	for _, n := range testCases {
		fmt.Printf("F(%d):\n", n)

		result, t := timeExec(func() int64 { return fibRecursive(n) })
		fmt.Printf("  Recursive:        %d  (%d us)\n", result, t.Microseconds())

		memo := make(map[int]int64)
		result, t = timeExec(func() int64 { return fibMemo(n, memo) })
		fmt.Printf("  Memoization:      %d  (%d us)\n", result, t.Microseconds())

		result, t = timeExec(func() int64 { return fibIterative(n) })
		fmt.Printf("  Iterative:        %d  (%d us)\n", result, t.Microseconds())

		result, t = timeExec(func() int64 { return fibOptimized(n) })
		fmt.Printf("  Space-optimized:  %d  (%d us)\n", result, t.Microseconds())

		result, t = timeExec(func() int64 { return fibMatrix(n) })
		fmt.Printf("  Matrix:           %d  (%d us)\n", result, t.Microseconds())

		result, t = timeExec(func() int64 { return fibBinet(n) })
		fmt.Printf("  Binet:            %d  (%d us)\n", result, t.Microseconds())

		fmt.Println()
	}
}

运行该程序将输出

=== Fibonacci Comparison ===

F(0):
  Recursive:        0  (0 us)
  Memoization:      0  (0 us)
  Iterative:        0  (0 us)
  Space-optimized:  0  (0 us)
  Matrix:           0  (0 us)
  Binet:            0  (0 us)

F(1):
  Recursive:        1  (0 us)
  Memoization:      1  (0 us)
  Iterative:        1  (0 us)
  Space-optimized:  1  (0 us)
  Matrix:           1  (0 us)
  Binet:            1  (0 us)

F(10):
  Recursive:        55  (3 us)
  Memoization:      55  (2 us)
  Iterative:        55  (1 us)
  Space-optimized:  55  (0 us)
  Matrix:           55  (2 us)
  Binet:            55  (1 us)

F(20):
  Recursive:        6765  (390 us)
  Memoization:      6765  (3 us)
  Iterative:        6765  (1 us)
  Space-optimized:  6765  (0 us)
  Matrix:           6765  (3 us)
  Binet:            6765  (1 us)

Go 语言版本使用 time.Now()time.Since() 进行计时,time.Duration.Microseconds() 转换为微秒。Go 的执行效率接近 C/C++。


斐波那契数的性质

各方法对比

方法 时间复杂度 空间复杂度 优点 缺点
递归法 O(2^n) O(n) 直观易懂,直接翻译数学定义 指数级时间,n > 40 后极慢
记忆化递归 O(n) O(n) 避免重复计算,思路清晰 需要额外存储空间,递归栈开销
迭代法 O(n) O(n) 简单高效,无递归栈溢出风险 需要额外数组存储
空间优化迭代法 O(n) O(1) 最实用的方法,空间效率最优 无法保存中间结果
矩阵快速幂法 O(log n) O(log n) 或 O(1) 对极大 n 最优 实现复杂,小规模无优势
通项公式法 O(1) O(1) 常数时间,理论上最快 浮点精度限制,n > 70 误差大

实际应用

  • 黄金比例(Golden Ratio):F(n+1)/F(n) 随着 n 增大趋近于 φ = (1+√5)/2 ≈ 1.618。这一比值广泛出现在艺术、建筑和自然界中。
  • 动态规划(Dynamic Programming)入门:斐波那契数列是学习 DP 的经典案例,展示了从暴力递归到记忆化再到迭代的优化过程。
  • 自然界中的斐波那契:向日葵的种子螺旋数、松果鳞片的排列、鹦鹉螺的壳体曲线等,都遵循斐波那契数列规律。
  • 算法与数据结构:斐波那契搜索、斐波那契堆等高级数据结构以斐波那契数列为基础。

整数溢出注意事项

在 C/C++ 中,long long 类型为 64 位,最大可表示的斐波那契数为 F(92) = 7540113804746346429。计算 F(93) 及以上时会溢出。各语言的处理方式:

语言 溢出处理
C/C++ long long 可到 F(92);更大值需使用大整数库如 GMP
Go int64 可到 F(92);可使用 math/big 包处理大数
Python 原生支持任意精度整数,无溢出问题

示例:各关键点的斐波那契数值

F(0)   = 0
F(1)   = 1
F(10)  = 55
F(20)  = 6765
F(30)  = 832040
F(50)  = 12586269025
F(92)  = 7540113804746346429   (long long 极限)
F(100) = 354224848179261915075  (需要大整数支持)
posted @ 2026-04-17 03:06  游翔  阅读(30)  评论(0)    收藏  举报