核心是将递归转为不增长调用栈的迭代操作:通过累加器实现尾递归、用循环模拟尾调用、以显式栈管理多路递归上下文、结合惰性求值控制计算规模。

核心是把递归过程变成不增长调用栈的操作——不是靠语言自动优化,而是靠结构设计让逻辑本身可迭代、可累积、可中断。
用累加器改写递归体
普通递归常在回归阶段做计算(比如 n * factorial(n-1)),导致必须保留上层状态;尾递归则把中间结果作为参数传下去,让每一步都“做完即走”。
- 阶乘原始写法:
factorial(n) = n * factorial(n-1)→ 回归时才乘,栈深随 n 增长 - 累加器写法:
factorial(n, acc = 1) = factorial(n-1, n * acc)→ 每次调用前就更新结果,无待处理运算 - 关键点:终止条件直接返回
acc,不再依赖上层返回值参与计算
用循环模拟尾递归执行
JavaScript、Python 等语言不支持真正的尾调用优化,但可以用 while 循环+状态变量完全等价替代。
- 把递归参数变成可变变量(如
n和acc) - 用
while (n > 0)替代递归调用,每次迭代更新状态 - fp-ts 的
tailRec就是这个思路:接收初始值和生成Either<a></a>的函数,Left继续,Right退出
用数据结构承载递归上下文
对多路递归(如树遍历、DFS),不能只靠单个累加器,需显式维护“下一步要做什么”。
- 用栈或队列存待处理节点 + 当前路径/状态,代替隐式调用栈
- 例如二叉树前序遍历:压栈时按“右→左”顺序,保证左子树先出;每次 pop 后处理当前节点,再 push 子节点
- 回溯类问题(如全排列):栈中存
(node, path_so_far)元组,避免闭包捕获和深层嵌套
用不可变数据 + 惰性求值控制规模
当递归用于生成大量中间结果(如展开嵌套列表、解析表达式树),避免一次性全量构造。
- 返回惰性结构(如 TypeScript 的
IterableIterator、Scala 的LazyList) - 递归函数只定义“如何取下一个”,不立即执行全部层级
- 结合
take(10)或find等操作提前终止,跳过后续计算











