我是递归的新手,并且一直在研究非尾递归。我相信这是递归调用不在函数末尾的地方。我在看一些递归代码示例,对于执行递归调用后的代码时间和方式感到困惑。更具体地说,当程序的当前行到达递归调用时,是在再次实际执行整个功能之前执行的最后一段代码,还是当前执行的行立即跳回到函数的开头,仅在整个递归触底之后执行剩余的代码位?有人可以说明这对我如何工作吗?
答案 0 :(得分:0)
在这里想象一下这段代码:(我在这里使用JS,但是它适用于所有热切的语言)
function add(a, b) {
return a + b;
}
function sub(a, b) {
return a - b;
}
function fib(n) {
if (n < 2) {
return n;
} else {
return add(
fib(sub(n, 2)),
fib(sub(n, 1)),
);
}
}
console.log(fib(10));
现在,当n
为2
时,我们将对两个前任调用fib的结果添加到n
中。某些调用之间的顺序是由JS引擎选择的,但是需要调用sub
并返回,然后fib
可以获取值并在两个参数都具有结果时调用add。可以使用延续传递样式将其重写为尾部调用:
function cadd(a, b, k) {
k(a + b);
}
function csub(a, b, k) {
k(a - b);
}
function cfib(n, k) {
if (n < 2) {
k(n);
} else {
csub(n, 2, n2 =>
cfib(n2, rn2 =>
csub(n, 1, n1 =>
cfib(n1, rn1 =>
cadd(rn2, rn1, k)))));
}
}
cfib(10, console.log);
在这里您看到引擎选择的顺序从左到右都是明确的。每个调用都做一件事,然后继续调用该结果。还要注意,这永远不会返回任何东西。 “返回”仅通过继续来完成,但其功能与之前的代码完全相同。
在许多语言中,它们都可以编译成相同的语言。