一尘不染

什么是尾递归?

algorithm

在开始学习Lisp的同时,我遇到了术语“ 尾递归” 。到底是什么意思?


阅读 275

收藏
2020-07-28

共1个答案

一尘不染

考虑一个简单的函数,该函数将前N个自然数相加。(例如sum(5) = 1 + 2 + 3 + 4 + 5 = 15)。

这是一个使用递归的简单JavaScript实现:

function recsum(x) {
    if (x === 1) {
        return x;
    } else {
        return x + recsum(x - 1);
    }
}

如果您调用recsum(5),这是JavaScript解释器将评估的内容:

recsum(5)
5 + recsum(4)
5 + (4 + recsum(3))
5 + (4 + (3 + recsum(2)))
5 + (4 + (3 + (2 + recsum(1))))
5 + (4 + (3 + (2 + 1)))
15

请注意,在JavaScript解释器开始实际执行计算总和之前,必须完成每个递归调用。

这是相同函数的尾递归版本:

function tailrecsum(x, running_total = 0) {
    if (x === 0) {
        return running_total;
    } else {
        return tailrecsum(x - 1, running_total + x);
    }
}

这是您调用时发生的事件序列tailrecsum(5)tailrecsum(5, 0)由于默认的第二个参数,实际上是)。

tailrecsum(5, 0)
tailrecsum(4, 5)
tailrecsum(3, 9)
tailrecsum(2, 12)
tailrecsum(1, 14)
tailrecsum(0, 15)
15

在尾部递归的情况下,每次对递归调用进行评估时,running_total都会更新。

注意:原始答案使用了Python中的示例。这些已更改为JavaScript,因为Python解释器不支持[尾部调用优化。但是,尽管尾部调用优化是ECMAScript
2015规范的一部分,但
大多数JavaScript解释器都不支持它

2020-07-28