递归

Recursion
用函数自身来定义函数的方法,使用有限的语句来定义无限对象的集合,用于描述自相似方法、重复事物的过程。
同时是重要的思维模式,使用递归基础递归公式/步骤两部分来定义。

“自上而下”地解决问题。将原问题分解为更小的子问题,这些子问题和原问题具有相同的形式。接下来将子问题继续分解为更小的子问题,直到基本情况时停止(基本情况的解是已知的)。

递归条件(recursive case):调用自身
基线条件(base case):不再调用自身(避免形成无限循环)

算法层面

是一种算法策略,通过函数调用自身来解决问题。它主要包含两个阶段。

  1. :程序不断深入地调用自身,通常传入更小或更简化的参数,直到达到“终止条件”。
  2. :触发“终止条件”后,程序从最深层的递归函数开始逐层返回,汇聚每一层的结果。

而从实现的角度看,递归代码主要包含三个要素。

  1. 终止条件:用于决定什么时候由“递”转“归”。
  2. 递归调用:对应“递”,函数调用自身,通常输入更小或更简化的参数。
  3. 返回结果:对应“归”,将当前递归层级的结果返回至上一层。

调用栈

递归函数每次调用自身时,系统都会为新开启的函数分配内存,以存储局部变量、调用地址和其他信息等。

尾递归

Tail recursion
如果函数在返回前的最后一步才进行递归调用,则该函数可以被编译器或解释器优化,使其在空间效率上与迭代相当。

递归树

当处理与“分治”相关的算法问题时,递归往往比迭代的思路更加直观、代码更加易读。不断递归调用下去,最终产生递归树。

从本质上看,递归体现了“将问题分解为更小子问题”的思维范式,这种分治策略至关重要。

原始递归函数

原始递归函数:由本原函数出发,经过有限次函数复合与递归构造的函数

1. 递归基础/本原函数

2. 递归公式

函数复合

h(x1,,xm)=f(g(x1,,xm),,gk(x1,,xm))

函数递归

h(0,x1,,xk)=f(x1,,xk)h(S(n),x1,,xk)=g(h(n,x1,,xk),n,x1,,xk)

例子:加法的定义

add (0, x)= P11(x)
add (S (n), x)=S (P13 (add (n, x), n, x))

完全递归

从后向前代入,找到一条计算的路径,再由前向后一次计算