SICP
递归与迭代
a linear recursive process
线性递归
function factorial(n) {
return n === 1
? 1
: n * factorial(n - 1);
}
a linear iterative process
线性迭代
function factorial(n) {
return fact_iter(1, 1, n);
}
function fact_iter(product, counter, max_count) {
return counter > max_count
? product
: fact_iter(counter * product,
counter + 1,
max_count);
}
The expansion occurs as the process builds up a chain of deferred operations (in this case, a chain of multiplications).The contraction occurs as the operations are actually performed. This type of process, characterized by a chain of deferred operations, is called a recursive process.
递归的特性在于延迟操作,先展开收集(生成执行链),后执行(真正执行)收缩
the second process does not grow and shrink. At each step, all we need to keep track of, for any n_n, are the current values of the names product, counter, and max_count. We call this an _iterative process.
迭代始终真实执行,不做展开收缩,需要自行处理留存计算中间值。
In contrasting iteration and recursion, we must be careful not to confuse the notion of a recursive process with the notion of a recursive function.
递归过程不是递归函数。
When we describe a function as recursive, we are referring to the syntactic fact that the function declaration refers (either directly or indirectly) to the function itself. But when we describe a process as following a pattern that is, say, linearly recursive, we are speaking about how the process evolves, not about the syntax of how a function is written.
线性递归与线形迭代指的 是过程演化(执行图像),不是语法(实际代码)
It will execute an iterative process in constant space, even if the iterative process is described by a recursive function. An implementation with this property is called tail-recursive.[3] With a tail-recursive implementation, iteration can be expressed using the ordinary function call mechanism, so that special iteration constructs are useful only as syntactic sugar.
在常量空间中执行迭代过程,即使迭代过程是由递归函数描述的,这种实现叫 尾递归。
尾递归即是迭代,迭代即可用循环来实现。
尾递归其实是一种特殊的递归调用情况,全程无展开收缩的递归函数调用应该无需保留中间栈,一层函数执行完直接跳出,但是由于js没有尾递归优化,所以该耗的内存并不会减少(因为依旧是递归函数形式,编译器未在执行完一个函数后将栈弹出),所以将尾递归再转为循环,才能真正做到优化。
所有的尾递归都可转为循环。
https://zhuanlan.zhihu.com/p/36587160
function fact(_n, _r) { // <= _n, _r 用作初始化变量
var n = _n;
var r = _r; // <= 将原来的 n, r 变量提出来编程迭代变量
function _fact(_n, _r) { // <= 迭代函数非常简单,就是更新迭代变量而已
n = _n;
r = _r;
}
_fact_loop: while (true) { // <= 生成一个迭代循环
if (n <= 0) {
return r;
} else {
_fact(n - 1, r * n); continue _fact_loop; // <= 执行迭代函数,并且进入下一次迭代
}
}
}
As a consequence, these languages can describe iterative processes only by resorting to special-purpose looping constructs such as do, repeat, until, for, and while.
在没有尾递归的语言中,只可通过一些循环构造来实现迭代