斐波那契数列的递归和迭代实现
一、斐波那契数列的数学定义
斐波那契数列(Fibonacci Sequence)的定义具有明确的递推关系,是算法实现的核心依据:
- 初始条件:F (0) = 0,F (1) = 1(注:部分场景以 F (1)=1,F (2)=1 为初始项,需根据业务需求统一标准,本文以 F (0) 为起始索引)
- 递推公式:对任意整数 n ≥ 2,F (n) = F (n-1) + F (n-2)
例如斐波那契数列的前10项为1,1,2,3,5,8,13,21,34,55
二、递归算法
递归算法的核心是 “将大问题拆解为同类小问题”,通过调用自身求解子问题,最终聚合得到原问题答案。这种实现方式与斐波那契数列的递推公式高度契合,代码简洁但需关注效率问题。
2.1 核心逻辑
递归实现的关键在于明确 “基线条件” 与 “递归拆解”
基线条件:当 n=1 或 n=2 时,直接返回初始值1.
递归拆解:当 n>2 时,将 F (n) 拆解为 F (n-1) 和 F (n-2) 两个子问题,通过递归调用获取子问题结果后相加,得到 F (n) 的值.
2.2 C++实现
long fibi(int n) {//递归算法if (n == 1 || n == 2)return 1;//基线条件return fibi(n - 1) + fibi(n - 2);//递归拆解
}
注意这里取用long类型,即64位有符号整数,其取值最大为2^63-1,因此最多只能算到斐波那契数列的第46位.当需要计算的位数极多时(如计算fibi(100)),可考虑使用可以保存更多位数的数据类型,而当内置数据类型也不满足需求时,可考虑自定义类型来保存大数字,比如利用数组来保存大数字的各个位上的数字,也可寻求第三方库的帮助
2.3 时间复杂度与空间复杂度分析
2.3.1 时间复杂度
递归算法的时间复杂度需分析 “总计算次数”.
总调用次数 = 各层节点数之和,近似为等比数列求和:
1+2+4+...+2^(n-1)=2^n
因此,时间复杂度为 O (2ⁿ)——指数级复杂度.当 n=30
时,调用次数约 100 万;n=40
时约 10 亿;n=50
时已超 1000 亿,完全无法实用。
显然,该算法效率极低,主要原因是大量的重复计算.例如计算fibi(20)时,fibi(2)被计算4181次,fibi(3)被计算2584次
2.3.2 空间复杂度
空间复杂度衡量算法[运行时占用的额外空间],该算法的空间消耗主要来自函数调用栈(存储每次递归调用的上下文,如参数、返回地址等)
递归算法的调用栈深度=[递归的最大层数]. 对于斐波那契递归:
- 计算fibi
(n)
时,递归会先一路拆解到fibi(1),此时调用栈的深度为n. - 后续回溯计算fibi(
n-2)
时,栈会逐步弹出上层调用,栈深度不会超过n.
因调用栈深度为n,且每层调用仅占用常数级空间,故空间复杂度为O(n).
注意,当n较大时,可能会触发"栈溢出"错误.
三、迭代算法
迭代算法通过循环结构,从初始项开始逐步计算中间结果,直至得到目标值.这种实现方式避免了重复计算和栈空间占用,效率远高于普通递归
3.1 核心逻辑
迭代实现的关键在于"状态保存"与"循环推进":
状态初始化:定义两个变量保存前两项结果
循环推进:从fibi(3)开始,每次先更新past和prev为上一轮循环结束后curr的前两项,再通过past和prev计算当前项(curr=past+prev)
终止条件:当执行n-2次循环后,得到目标值
3.2 C++实现
long fibr(int n) {//递归算法long past, prev, curr;//临时变量分别存储第k-2,k-1,k项的值(k为循环次数+2)past = prev = curr = 1;//初始化for(int i=3;i<=n;i++){//不断递归计算下一项值past = prev;//存储fibr(i-2)prev = curr;//存储fibr(i-1)curr = past + prev;//存储fibr(i)}return curr;
}
3.3 时间复杂度和空间复杂度分析
3.3.1 时间复杂度
迭代算法的时间复杂度由"循环次数"决定.
该算法执行n-2次循环,原因:
第一次for循环,目标为fibr(3).past表示fibr(1),prev表示fibr(2),curr由两者相加,表示fibr(3);
第二次for循环,目标为fibr(4).past表示fibr(2),prev表示fibr(3),curr由两者相加,表示fibr(4);
第k次for循环将会得到fibr(k+2)的值.past是fibr(k+2)前二位,prev是fibr(k+2)前一位,curr由这两位相加得到fibr(k+2)的值
进入下一次循环,目标为fibr(k+3).此时past利用prev保持与目标值的相对位置,prev由curr保持与目标值的相对位置,最终curr由两值相加得到目标值
令k+2=n,则k=n-2,即需要进行n-2次循环即可得到目标值.
因此时间复杂度为 O (n),即线性级时间复杂度
3.3.2 空间复杂度
迭代算法仅使用变量复用保存状态,无论n多大,变量数量始终不变,因此空间复杂度为O(1),即常数级空间复杂度
四、总结
斐波那契数列的两种基础实现——递归与迭代,分别代表了"分治"与"递推"两种算法思想:
- 递归实现比迭代实现慢得多的原因:递归频繁调用栈,且有大量重复计算;而迭代仅用循环和变量复用实现
- 递归的优势在于代码简洁,可读性高,但其指数级时间复杂度和栈溢出风险限制了实际应用
- 迭代通过状态保存与循环推进,实现了O(n)时间复杂度和O(1)空间复杂度,性能较好