写点什么

要不要重新认识一下递归与迭代?

用户头像
西了意
关注
发布于: 2020 年 04 月 29 日
要不要重新认识一下递归与迭代?

最近在学习新加坡国立大学出品的 SICP JS 适配版。学到一个非常有意思的基础概念区分:递归与迭代



但凡有过编程经验的同学,都不会觉得自己不知道递归与迭代:递归就是自己调自己,迭代就是 for 或 while 嘛,很简单的事。



但这其实只是表面。



下面让我们重新认识一下递归和迭代,建立一点更深入的理解。



不废话,直接代码说话。



以阶乘问题 fact(4) 为例。递归:

// recursive process
function fact(n) {
return n === 0
? 1
: n * fact(n - 1)
}

以上代码计算 fact(4) 时产生的计算过程:

fact(4)
4 * fact(3)
4 * 3 * fact(2)
4 * 3 * 2 * fact(1)
4 * 3 * 2 * 1 * fact(0)
4 * 3 * 2 * 1 * 1
4 * 3 * 2 * 1
4 * 3 * 2
4 * 6
24



下面看迭代:

// iterative process
function fact(n) {
function fact_iter(a, n) {
return n === 0
? a
: fact_iter(a * n, n - 1)
}
return fact_iter(1, n)
}

计算 fact(4) 时产生的计算过程:

fact(4)
fact_iter(1, 4)
fact_iter(4, 3)
fact_iter(12, 2)
fact_iter(24, 1)
fact_iter(24, 0)
24



我们并没有使用 for 或者 while,也同样写出了迭代代码。是的,有些同学可能看出来了,这个迭代代码,其实就是我们通常所说的尾递归。而我们也知道,之所以叫尾递归,是因为尾递归代码可以被编译器优化为迭代。



是的,迭代和递归,指的是计算过程的展开形式,而非函数自我调用或者 for, while 的区别。



最后,我贴一个指数快速计算的对比代码,感兴趣的同学,可以自己手绘一下计算过程的图示,感知一下递归和迭代的区别。

// recursive process
function fast_expt(b, n) {
return n === 0
? 1
: is_even(n)
? square(fast_expt(b, n / 2))
: b * fast_expt(b, n - 1);
}
// iterative process
function fast_expt(b, n) {
function iter(a, b, count) {
return count === 0
? a
: is_even(count)
? iter(a, square(b), count / 2)
: iter(a * b, b, count - 1);
}
return iter(1, b, n);
}
function is_even(x) {
return x % 2 === 0;
}
function square (x) {
return x * x;
}



发布于: 2020 年 04 月 29 日阅读数: 53
用户头像

西了意

关注

不吐不快 2017.12.20 加入

大龄物理专业转行程序员

评论

发布
暂无评论
要不要重新认识一下递归与迭代?