尾递归

求斐波纳契数列的递归函数,一般来说我们会这么写:


def fib_normal(n):
    return n <= 2 and 1 or fib_normal(n-1) + fib_normal(n-2)

这当然是典型的费力不讨好的写法,弱智的教科书上都会这么写,还常常表达斐波纳契数列不是O(N)的效率,这么多年坑了不少人。这里只是引出尾递归,写了这么没效率的函数。

执行这个函数的时候,解释器每调用一次fib_normal都会开辟新的堆栈,假如每个堆栈需要K字节的缓冲区,那么计算出结果需要O(NlogN)*K大小的栈空间,如果N很大,就可能会溢出。

现在考虑另一种思路:把计算结果传下去,然后废掉本层栈空间,总的下来只用K大小的缓冲。这就是尾递归的本质,看一看使用尾递归的斐波纳契数列:


def fib_endr(n, a, b):
    return n == 2 and b or fib_endr(n-1, b, a + b)

舒爽了不少。