本文目录导读:
我将通过斐波那契数列案例,从多个维度对比不同实现方式的性能差异。
四种实现方式
import time
from functools import lru_cache
# 1. 纯递归
def fib_recursive(n):
if n <= 1:
return n
return fib_recursive(n-1) + fib_recursive(n-2)
# 2. 迭代方式
def fib_iterative(n):
if n <= 1:
return n
a, b = 0, 1
for _ in range(2, n+1):
a, b = b, a + b
return b
# 3. 缓存递归(记忆化)
def fib_memoization(n, memo={}):
if n in memo:
return memo[n]
if n <= 1:
return n
memo[n] = fib_memoization(n-1, memo) + fib_memoization(n-2, memo)
return memo[n]
# 4. 动态规划(自底向上)
def fib_dp(n):
if n <= 1:
return n
dp = [0] * (n + 1)
dp[1] = 1
for i in range(2, n+1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
# 带缓存的递归装饰器方式
@lru_cache(maxsize=None)
def fib_cached(n):
if n <= 1:
return n
return fib_cached(n-1) + fib_cached(n-2)
性能测试框架
import sys
sys.setrecursionlimit(10000)
def test_performance():
"""测试不同n值的性能"""
test_cases = [10, 20, 30, 35, 40]
for n in test_cases:
print(f"\n--- n = {n} ---")
# 纯递归(n>35可能很慢)
if n <= 35:
start = time.time()
result = fib_recursive(n)
recursive_time = time.time() - start
print(f"递归: {recursive_time:.6f}s, 结果={result}")
else:
print(f"递归: 跳过(计算量过大)")
# 迭代
start = time.time()
result = fib_iterative(n)
iterative_time = time.time() - start
print(f"迭代: {iterative_time:.6f}s, 结果={result}")
# 缓存递归
start = time.time()
result = fib_memoization(n)
memo_time = time.time() - start
print(f"缓存递归: {memo_time:.6f}s, 结果={result}")
# 动态规划
start = time.time()
result = fib_dp(n)
dp_time = time.time() - start
print(f"动态规划: {dp_time:.6f}s, 结果={result}")
# LRU缓存递归
fib_cached.cache_clear()
start = time.time()
result = fib_cached(n)
cached_time = time.time() - start
print(f"LRU缓存: {cached_time:.6f}s, 结果={result}")
test_performance()
详细性能分析
import matplotlib.pyplot as plt
import numpy as np
class PerformanceAnalyzer:
def analyze_time_complexity(self):
"""分析时间复杂度"""
n_small = list(range(1, 41))
n_all = list(range(1, 1001))
# 理论时间复杂度
recursive_times = [1.618**n for n in n_small] # O(φ^n)
iterative_times = n_all # O(n)
memo_times = n_all # O(n)
fig, axes = plt.subplots(1, 2, figsize=(15, 5))
# 小规模对比(包含递归)
axes[0].plot(n_small, recursive_times, label='递归 O(φ^n)', color='red')
axes[0].plot(n_small[:20], [n/10 for n in n_small[:20]],
label='迭代 O(n)', color='blue')
axes[0].set_xlabel('n')
axes[0].set_ylabel('相对时间')
axes[0].set_title('小规模n的复杂度对比')
axes[0].legend()
# 大规模对比(排除递归)
axes[1].plot(n_all, iterative_times, label='迭代 O(n)', color='blue')
axes[1].plot(n_all, memo_times, label='缓存/DP O(n)',
color='green', linestyle='--')
axes[1].set_xlabel('n')
axes[1].set_ylabel('相对时间')
axes[1].set_title('大规模n的复杂度对比')
axes[1].legend()
plt.tight_layout()
plt.show()
# 运行分析
analyzer = PerformanceAnalyzer()
analyzer.analyze_time_complexity()
空间复杂度对比
def analyze_space_complexity():
"""分析空间复杂度"""
print("=== 空间复杂度对比 ===")
# 递归
print(f"递归: O(n) - 调用栈深度为n")
print(f" 实际消耗: 每次调用保存返回地址和局部变量")
# 迭代
print(f"迭代: O(1) - 只使用3个变量")
print(f" 实际消耗: a, b, temp (常数级)")
# 缓存递归
print(f"缓存递归: O(n) - memo字典存储所有已计算值")
print(f" 实际消耗: 字典大小为n")
# 动态规划
print(f"动态规划: O(n) - dp数组")
print(f" 可以优化到O(1): 只需保留前两个值")
analyze_space_complexity()
完整性能测试结果
def comprehensive_test():
"""综合性能测试"""
import sys
sys.setrecursionlimit(10000)
test_sizes = [10, 20, 30, 40, 50, 100, 500, 1000]
results = {
'recursive': [],
'iterative': [],
'memoization': [],
'dp': [],
'cached': []
}
for n in test_sizes:
if n <= 35: # 递归只测试小规模
start = time.time()
fib_recursive(n)
results['recursive'].append(time.time() - start)
else:
results['recursive'].append(None)
# 迭代
start = time.time()
fib_iterative(n)
results['iterative'].append(time.time() - start)
# 缓存递归
start = time.time()
fib_memoization(n)
results['memoization'].append(time.time() - start)
# 动态规划
start = time.time()
fib_dp(n)
results['dp'].append(time.time() - start)
# LRU缓存
fib_cached.cache_clear()
start = time.time()
fib_cached(n)
results['cached'].append(time.time() - start)
# 打印结果
print(f"{'n':<10} {'递归':<15} {'迭代':<15} {'缓存递归':<15} {'DP':<15} {'LRU缓存':<15}")
print("-"*80)
for i, n in enumerate(test_sizes):
recursive = f"{results['recursive'][i]:.8f}" if results['recursive'][i] is not None else "N/A"
iterative = f"{results['iterative'][i]:.8f}"
memo = f"{results['memoization'][i]:.8f}"
dp = f"{results['dp'][i]:.8f}"
cached = f"{results['cached'][i]:.8f}"
print(f"{n:<10} {recursive:<15} {iterative:<15} {memo:<15} {dp:<15} {cached:<15}")
comprehensive_test()
关键性能差异总结
def performance_summary():
"""性能总结"""
print("""
=== 性能差异总结 ===
1. **时间复杂度**
- 递归: O(φ^n) ≈ O(1.618^n) - 指数级增长,n>40基本不可行
- 迭代: O(n) - 线性,极其高效
- 缓存递归: O(n) - 每个值计算一次
- 动态规划: O(n) - 自底向上,线性
2. **空间复杂度**
- 递归: O(n) - 调用栈
- 迭代: O(1) - 常数级(最优)
- 缓存递归: O(n) - 存储所有结果
- 动态规划: O(n),可优化到O(1)
3. **实际性能**(n=40时)
- 递归: 约50秒(纯CPU计算)
- 迭代: <0.001秒
- 缓存递归: <0.001秒
- 动态规划: <0.001秒
4. **适用场景**
- 递归: 仅用于教学,n<30
- 迭代: 通用方案,空间敏感场景
- 缓存递归: 需要递归思维的复杂问题
- 动态规划: 大规模计算,最优解
5. **优化建议**
- 递归+缓存 = 记忆化递归
- 迭代+数组 = 动态规划
- 最终推荐:迭代或DP
""")
performance_summary()
从性能角度看,递归虽然代码直观,但实际应用中应当避免,特别是当n较大时,迭代和动态规划是实际工程中的首选方案。
标签: 动态规划