递归为什么会爆栈:主定理之外的工程现实

主定理只算"时间",不算"栈"。深层递归每层都要压一个调用帧,过深就栈溢出。本文讲清递归 vs 迭代的栈代价,以及如何用尾递归/迭代改写规避。
图:递归每层的调用帧占栈,过深则栈溢出;迭代只需常量栈
主定理给出的是时间复杂度,但它完全不关心栈空间。每次递归调用都会在调用栈上压一帧,深度为 的递归就要占 栈。当 与 同阶(如链表递归、某些分治),栈高可能达到 ,一旦超过栈上限就 栈溢出(stack overflow)。
递归 vs 迭代
同样的算法,迭代写法往往只需 栈(一个循环变量)。所以工程上常把尾递归改写成循环,或显式用栈/队列模拟递归,把 栈压成 。
参考代码:递归改迭代,避免爆栈
# 递归版(深度 n 时占 O(n) 栈,可能溢出)
def factorial_rec(n):
return 1 if n <= 1 else n * factorial_rec(n - 1)
# 迭代版(仅占 O(1) 栈)
def factorial_iter(n):
r = 1
for i in range(2, n + 1):
r *= i
return r
print(factorial_iter(5)) # 120
经验法则:能用迭代/尾递归就别用深层线性递归;分治递归深度通常只有 (如二分、归并),栈压力小,相对安全;但"每次减 1"的递归深度 ,务必改写成循环。
关联推荐
- 二分查找:20 行代码里藏着的对数级智慧 — 递归深度仅 Θ(log n),栈压力小
- 插入、选择、冒泡排序(KU) — 排序递推深度也是对数级
- 算法与问题求解入门(KU) — 递归作为算法基本思想
评论 (0)
正文划词可点「问萝卜特」——自动发评论并由 AI 回复
加载评论中…