Python学习算法系列(2):递归算法基础
1. 引言
递归(Recursion) 是一种在函数内部调用自身的编程技巧,广泛应用于:
- 数学计算(阶乘、斐波那契数列)
- 数据结构(树、图遍历)
- 回溯算法(八皇后、全排列)
本篇博客将介绍:
- 递归的基本概念
- 递归的实现方式
- 递归的常见问题
- 如何优化递归
2. 什么是递归?
递归函数 是一个调用自身的函数,并且必须有终止条件,否则会导致无限递归(死循环)。
📌 示例:求 n 的阶乘(n!)
def factorial(n):
if n == 0: # 终止条件
return 1
return n * factorial(n - 1) # 递归调用
print(factorial(5)) # 输出 120
📌 解释
factorial(5) = 5 * factorial(4)
factorial(4) = 4 * factorial(3)
- …
factorial(1) = 1 * factorial(0)
factorial(0) = 1
(终止)
✅ 递归核心:必须有终止条件,否则会无限递归!
3. 递归的执行过程
以 factorial(5)
为例,递归的调用栈如下:
factorial(5) -> 5 * factorial(4)
factorial(4) -> 4 * factorial(3)
factorial(3) -> 3 * factorial(2)
factorial(2) -> 2 * factorial(1)
factorial(1) -> 1 * factorial(0)
factorial(0) -> 1 (终止条件)
然后依次返回:
factorial(1) = 1 * 1 = 1
factorial(2) = 2 * 1 = 2
factorial(3) = 3 * 2 = 6
factorial(4) = 4 * 6 = 24
factorial(5) = 5 * 24 = 120
✅ 递归执行是“先递归,后回溯”
4. 递归的应用场景
4.1 斐波那契数列
def fibonacci(n):
if n <= 1: # 终止条件
return n
return fibonacci(n - 1) + fibonacci(n - 2) # 递归调用
print(fibonacci(6)) # 输出 8
📌 问题
- 递归调用次数太多,导致性能低
- 例如
fibonacci(6)
需要计算fibonacci(5)
和fibonacci(4)
,而fibonacci(5)
又需要计算fibonacci(4)
和fibonacci(3)
,会有大量重复计算
✅ 优化方法:使用记忆化存储
4.2 递归遍历树结构
class Node:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def preorder_traversal(node):
if node is None:
return
print(node.value, end=" ") # 先访问根节点
preorder_traversal(node.left) # 递归遍历左子树
preorder_traversal(node.right) # 递归遍历右子树
# 构造二叉树
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
preorder_traversal(root) # 输出 1 2 4 5 3
✅ 递归非常适合树形结构的数据处理
5. 递归的优化(尾递归 & 记忆化)
5.1 尾递归优化
尾递归是指递归调用发生在函数的最后一步,Python 没有内置尾递归优化,但可以用循环代替递归。
📌 尾递归示例
def factorial_tail(n, acc=1):
if n == 0:
return acc
return factorial_tail(n - 1, acc * n)
print(factorial_tail(5)) # 输出 120
✅ 但 Python 不支持真正的尾递归优化,可以用循环替代
5.2 记忆化存储(Memoization)
📌 优化斐波那契数列
from functools import lru_cache
@lru_cache(None)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(50)) # 运行速度显著提升!
✅ @lru_cache
避免重复计算,提高效率
6. 递归 vs 迭代
方式 | 优点 | 缺点 |
---|---|---|
递归 | 代码简洁、易理解 | 可能导致栈溢出,性能较低 |
迭代 | 运行效率高,不会栈溢出 | 代码可能较复杂 |
📌 示例:斐波那契的迭代实现
def fibonacci_iter(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
print(fibonacci_iter(50)) # 运行更快
✅ 推荐使用 迭代 + 记忆化 优化递归
7. 总结
✅ 递归的特点
- 必须有终止条件
- 适用于分治问题、树结构遍历等
- 可能导致栈溢出,需要优化
✅ 如何优化递归
- 使用尾递归
- 使用
lru_cache
记忆化存储 - 用迭代替代递归
📢 下一篇 Python学习算法系列(3):排序算法(冒泡排序 & 选择排序),敬请期待!🚀
💡 如果你喜欢这篇文章,欢迎点赞、收藏,并关注本系列!