[C/C++入门][for]24、菲波那契数列

斐波那契数列是数学中的一个经典数列,以其独特的递归性质而闻名。

数列的前两项通常是0和1(或者有时从1开始,当然这个不是强制要求),之后的每一项都是前两项的和。数列的前几项如下所示:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ......

斐波那契数列在自然界、艺术、建筑以及金融领域都有广泛的体现和应用,它还与黄金分割比例有关联。

我们可以用按照这个规律来实现斐波那契数列的计算——步骤:

  1. 初始化

    确定迭代的起始条件。对于斐波那契数列,前两项分别为F(0)=0和F(1)=1,所以需要初始化两个变量,分别代表当前项和前一项。
  2. 设定循环

    设定一个循环结构,从初始状态开始,逐步向目标状态推进。对于求解第n项,循环的次数应当是从2到n。
  3. 更新状态

    在每一次循环中,根据当前的状态计算新的状态。对于斐波那契数列,就是将前两项相加得到当前项。更新变量,将当前项赋值给前一项,将新计算出的当前项赋值给当前项变量。
  4. 终止条件

    循环应该有一个明确的终止条件。对于求解第n项,当循环计数器达到n时,循环结束。
  5. 返回结果

    当循环结束后,最后一个计算出的当前项即为所求的斐波那契数列的第n项。
#include <iostream>
using namespace std;

unsigned long fibonacci(unsigned int n) {
    // Step 1: 初始化
    if (n <= 1) return n;
    
    unsigned long prev = 0, curr = 1;
    
    // Step 2: 设定循环
    for (unsigned int i = 2; i <= n; ++i) {
        // Step 3: 更新状态
        unsigned long next = prev + curr;
        prev = curr;
        curr = next;
    }
    
    // Step 5: 返回结果
    return curr;
}

int main() {
    unsigned int n;
    cout << "请输入想要求解的斐波那契数列的项数:";
    cin >> n;
    cout << "斐波那契数列的第" << n << "项是:" << fibonacci(n) << endl;
    return 0;
}

 这是一种非常常见的方法。还有比如递归,动态规划等。可以作为了解。

(扩展)递归

斐波那契数列定义为:F(0) = 0, F(1) = 1, F(n) = F(n-1) + F(n-2) (n > 1)。

unsigned long fibonacci_recursive(unsigned int n) {
    if (n <= 1) // 基本情况
        return n;
    else // 递归情况
        return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2);
}

只要从高到底不断加就可以。

(扩展)动态规划

动态规划是一种优化的递归方法,主要针对那些具有重叠问题和最优子结构特征的问题。

它通过存储子问题的解来避免重复计算,从而大大提高了效率。

动态规划有两种主要形式:自底向上自顶向下带备忘录(记忆功能)。

  • 自底向上:从最小的子问题开始,逐步构建到最终的解。
  • 自顶向下带备忘录:从大问题开始,遇到已解决的子问题就直接使用其解,避免重复计算。
unsigned long fibonacci_dp(unsigned int n) {
    if (n <= 1)
        return n;
    
    unsigned long fib[n+1];
    fib[0] = 0;
    fib[1] = 1;
    
    for (unsigned int i = 2; i <= n; i++) {
        fib[i] = fib[i-1] + fib[i-2];
    }
    
    return fib[n];
}

(扩展)结合递归和动态规划的一种效率高的方法。

unsigned long fibonacci_memo(unsigned int n, unsigned long memo[]) {
    if (memo[n] != -1)
        return memo[n];
    
    if (n <= 1)
        memo[n] = n;
    else
        memo[n] = fibonacci_memo(n-1, memo) + fibonacci_memo(n-2, memo);
    
    return memo[n];
}

unsigned long fibonacci_memo_topdown(unsigned int n) {
    unsigned long memo[n+1];
    for (unsigned int i = 0; i <= n; i++)
        memo[i] = -1;
    
    return fibonacci_memo(n, memo);
}

这是一种结合了递归与动态规划优点的技术。这种方法的核心思想是在递归的过程中,对已经计算过的结果进行缓存,这样当下次需要同样的结果时,就可以直接从缓存中读取,而不需要重新计算,这极大地提升了效率,尤其是在处理具有大量重复子问题的情况时。

让我们再次以斐波那契数列为例来深入解释这一过程:

假设我们想要计算F(n),即第n个斐波那契数。按照递归的思路,我们会首先尝试计算F(n-1)F(n-2),然后将这两个结果相加得到F(n)。但是,在计算F(n-1)F(n-2)的过程中,我们又会遇到更多的子问题,比如F(n-2)F(n-3)等等。如果我们不采取任何措施,那么对于F(n-2),我们会在计算F(n-1)F(n)时重复计算两次。

步骤解析:

  1. 初始化备忘录:创建一个数组或哈希表作为备忘录,用于存储之前计算过的子问题的答案。通常,我们初始化所有值为-1或某个特殊标记,表示这些值尚未被计算。

  2. 递归计算

    • 当我们需要计算某个子问题F(i)时,首先检查备忘录中是否已经有了F(i)的结果。
    • 如果有,直接返回该结果;如果没有,按照递归公式计算F(i),并将结果存入备忘录中。
  3. 返回最终结果:当递归到达基本情况时,直接返回结果,否则返回备忘录中存储的计算结果。

代码实现带注释:

unsigned long fibonacci_memo(unsigned int n, unsigned long memo[]) {
    // 如果结果已经计算过,直接返回
    if (memo[n] != -1)
        return memo[n];
    
    // 基本情况
    if (n <= 1)
        memo[n] = n;
    else {
        // 计算并存储结果
        memo[n] = fibonacci_memo(n-1, memo) + fibonacci_memo(n-2, memo);
    }
    
    // 返回计算结果
    return memo[n];
}

unsigned long fibonacci_memo_topdown(unsigned int n) {
    unsigned long memo[n+1];
    // 初始化备忘录
    for (unsigned int i = 0; i <= n; i++)
        memo[i] = -1;
    
    // 开始递归计算
    return fibonacci_memo(n, memo);
}

这个理解稍微会难一点,初学者可能理解不了。我们可以作为扩展阅读,等后面学到这我们回来再看这个问题。

  • 16
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值