递归函数入门:以阶乘和斐波那契数列为例

自己调用自己的函数,看似绕晕,却是解决很多问题的利器。

👋 你好,我是 Evan ,一名计算机专业的学长,也是《大一突围》专栏的作者。刚学递归时,我对着 factorial(n) 看了半天,死活想不通"函数为什么能调用自身"。直到画了几次调用栈,才豁然开朗。今天我就用阶乘和斐波那契数列这两个经典例子,带你彻底搞懂递归------不只是语法,更是背后的思维模型。

欢迎来到 《大一突围》 专栏。

一、什么是递归?

递归就是函数在定义中调用自身。它把一个复杂问题分解成规模更小的子问题,直到达到最简单的"基准条件"。

递归的两个核心要素

  • 基准条件(base case) :不再递归,直接返回结果。例如阶乘中 0! = 1

  • 递归条件(recursive case):将问题缩小,调用自身。

调用栈可视化

当你调用 factorial(3) 时,栈的变化如下:

二、案例一:阶乘(factorial)

数学定义:

  • 0! = 1

  • n! = n × (n-1)!

2.1 Python 实现

python 复制代码
def factorial(n):
    # 基准条件
    if n == 0:
        return 1
    # 递归条件
    return n * factorial(n - 1)

print(factorial(5))  # 输出 120

2.2 Java 实现

java 复制代码
public class Factorial {
    public static int factorial(int n) {
        if (n == 0) return 1;
        return n * factorial(n - 1);
    }
    public static void main(String[] args) {
        System.out.println(factorial(5)); // 120
    }
}

2.3 执行过程(n=3)

  1. factorial(3) → 3 × factorial(2)

  2. factorial(2) → 2 × factorial(1)

  3. factorial(1) → 1 × factorial(0)

  4. factorial(0) → 1

  5. 返回:1 ← 1×1 ← 2×1 ← 3×2 = 6

三、案例二:斐波那契数列

数学定义:

  • F(0) = 0, F(1) = 1

  • F(n) = F(n-1) + F(n-2)

3.1 朴素递归实现

python 复制代码
def fib(n):
    if n <= 1:
        return n
    return fib(n-1) + fib(n-2)

print(fib(10))  # 55

3.2 调用树(n=5)

可以看到 fib(2) 被重复计算多次,导致指数级时间复杂度 O(2^n)。

四、递归优化:记忆化(Memoization)

用字典或数组缓存已经计算过的值,避免重复递归。

4.1 Python 记忆化

python 复制代码
python

def fib_memo(n, memo={}):
    if n in memo:
        return memo[n]
    if n <= 1:
        return n
    memo[n] = fib_memo(n-1, memo) + fib_memo(n-2, memo)
    return memo[n]

print(fib_memo(50))  # 瞬间出结果

4.2 Java 使用数组缓存

python 复制代码
java

public class Fibonacci {
    private static long[] memo;
    public static long fib(int n) {
        if (n <= 1) return n;
        if (memo[n] != 0) return memo[n];
        memo[n] = fib(n-1) + fib(n-2);
        return memo[n];
    }
    public static void main(String[] args) {
        memo = new long[51];
        System.out.println(fib(50));
    }
}

优化后时间复杂度:O(n),空间复杂度 O(n)。

五、递归 vs 迭代(循环)

阶乘的迭代实现

python 复制代码
python

def factorial_iter(n):
    result = 1
    for i in range(1, n+1):
        result *= i
    return result

斐波那契的迭代实现

python 复制代码
python

def fib_iter(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return a

六、常见递归陷阱与解决方案

七、总结与思考

  • 递归的本质:把大问题拆成同类型的小问题,直到可以直接解决。

  • 何时使用递归:问题天然具有递归结构(如树遍历、汉诺塔、快速排序)。

  • 何时避免递归:深度大、性能敏感、语言栈限制严(如 Python)。

递归就像俄罗斯套娃,最大的娃娃里装着稍小的,最小的不能再拆了,然后一个个打开,得到最终答案。

❓ 问题:你第一次理解递归时用的是什么例子?或者你在写递归时遇到过栈溢出吗?有没有什么妙招?欢迎在评论区分享,我会选出 3 位同学,送出《递归算法经典题目集锦》和《记忆化模板代码》。

📌 如果本文帮你打通了递归的任督二脉,请点 👍 赞 + 关注 ,本专栏 《大一突围》 持续输出编程基础与思维干货。

收藏本文,下次遇到递归题回来复习,画调用栈永远不过时。

相关推荐
地平线开发者1 天前
J6B vio scenario sample
算法
SelectDB1 天前
Apache Doris Python UDF:让 SQL 直接调用 Python 生态,支撑 Agent 时代复杂业务逻辑
大数据·数据库·python
BothSavage2 天前
Trae远程开发中DeepSeek自定义模型4054错误的排查与修复
算法
小林ixn2 天前
从暴力到KMP:一道题彻底搞懂字符串匹配的前世今生
算法
烬羽2 天前
字符串算法入门:从反转字符串到回文判断,面试不再慌
算法·面试
荣码2 天前
GraphRAG:普通RAG只能回答"点"的问题,我踩了4个坑才搞懂
java·python
金銀銅鐵2 天前
[Python] 基于欧几里得算法,实现分数约分计算器
python·数学
Lyn_Li2 天前
Kaggle Top 5 | 198只股票、200条数据的金融预测——BattleFin高分方案从零复现
python·kaggle·比赛复盘·金融预测