关于递归、PTC、TCO

254 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情

递归

谈到递归。大家应该不陌生。在开发中可能经常会使用到递归函数。一般开发场景递归调用次数较少。不会有什么问题。但是如果把递归用在算法中。当递归调用次数过多时。就出出现报错。这也是javascript的一种自我保护机制。比如说大多数人的算法入门,斐波那契数列。

function fibonacci(n){
    if(n<=2) return 1
    return fibonacci(n-1)+fibonacci(n-2)
}

console.log(fibonacci(10))

如果把这个函数在本地或者浏览器执行。n传入值较大,则会直接导致浏览器卡死。

写一个函数把n以下的数字相乘的函数。

function test(n){
    if(n<1) return 1
    return n*test(n-1)
}
console.log(test(10))
console.log(test(10000))

函数传入参数10的时候会正常执行。在1后面多加几个0之后。则无法正常输出结果。会得到报错。Maximum call stack size exceeded。我在本地执行代码的。在chrome中运行也是一样的结果。

image.png

那怎么能把这个函数优化。使浏览器可以输出正常的值呢?

PTC(Proper Tail Call)

下面的这种改写方式为尾调用。尾调用

function test(n){
    if(n===0){
        return 1
    }
    return n*test(n-1)
}
console.log(test(100))

在函数内部我们也可以使用console.trace()方法来观察调用栈。

PTC尾调用可以被优化。

TCO(Tail Call Optimization) 尾递归优化

PTC可以优化为TCO的方式。

function test(n, total = 1) {
    if (n === 0) {
        return total
    }
    return test(n - 1, n * total)
}

注意执行上面代码输入大数据是。依然会抛出error。必须要实现ES6引擎中运行代码。才会得到真实的结果。

总结

TC0优化并非唯一的优化手段。通过其他的方式优化。也可以实现对于函数的优化。比如对于斐波那契数列的优化。

function fibonacci(n){
    if(n<=2) return 1
    let n1 = 1
    let n2=2
    for(let i=3;i<n;i++){
        let temp = n1
        n1 = n2
        n2 = temp+n2
    }
    return n2
}