简体   繁体   English

斐波那契 function 的尾递归版本

[英]tail recursive version of the fibonacci function

I am having trouble understanding the concept of tail recursion, I want to make a tail recursive version of the fibonacci function and so far this is what I came up with but I don't know if its correct or not,can someone help me out, any help would be appreciated我无法理解尾递归的概念,我想制作斐波那契 function 的尾递归版本,到目前为止这是我想出的,但我不知道它是否正确,有人可以帮我, 任何帮助,将不胜感激

#include <stdio.h>

int fibonacci(int n)
{
    if(n==1)return 1;
    if(n==2)return 1;
    return fibonacci(n-1)+fibonacci(n-2);
}


int fibonacci_tail_Recusive(int n,int prev1,int prev2)
{
    
    if(n<0) return -1;
    if(n==1||n==0) return prev2;
    return fibonacci_tail_Recusive(n-1,prev2+prev1,prev1);
}

int fibonacci_tail_Recusive_wrapper(int n)
{
    return fibonacci_tail_Recusive(n,1,1);
}


int main()
{
    printf("tail recursive result: %d  normal recursive result:%d", fibonacci_tail_Recusive_wrapper(23) ,fibonacci(23));

    return 0;
}

the code compiles and outputs the correct result代码编译并输出正确的结果

int fibonacci_tail_Recusive(int n,int prev1,int prev2)
{
    
    if(n<0) return -1;
    if(n==1||n==0) return prev2;
    return fibonacci_tail_Recusive(n-1,prev2+prev1,prev1);
}

This function is, correctly, tail-recursive.这个 function 正确地是尾递归的。

A tail-recursive function is one where all the paths end (ie, return ) either a value (-1 for negative, prev2 for 1 and 0) or a call to a function (it doesn't need to be itself directly; though if it doesn't call itself either directly or indirectly it wouldn't be tail-recursive).尾递归 function 是所有路径都结束(即return )一个值(-1 表示负数, prev2表示 1 和 0)或对 function 的调用(它不需要直接是它自己;虽然如果它不直接或间接地调用自己,它就不是尾递归的)。

Fibonacci isn't a great example to show tail-recursion because here it muddles the benefit of tail-recursion (being equivalent to an iterative loop) with the optimization of avoiding redundant calls (the original fibonacci function calls itself twice in the final case).斐波那契不是展示尾递归的好例子,因为在这里它混淆了尾递归(相当于迭代循环)的好处和避免冗余调用的优化(原始fibonacci那契 function 在最后一种情况下调用自己两次) .

Consider the factorial function:考虑factorial function:

int factorial(int n)
{
    if (n == 0 || n == 1) return 1;
    return factorial(n - 1) * n;
}

When you call factorial(5), the call stack looks like this:当您调用 factorial(5) 时,调用堆栈如下所示:

factorial(5)
   5 * factorial(4)
   5 * (4 * factorial(3))
   5 * (4 * (3 * factorial(2)))
   5 * (4 * (3 * (2 * factorial(1))))
   5 * (4 * (3 * (2 * 1)))
   5 * (4 * (3 * 2))
   5 * (4 * 6)
   5 * 24
   120

at each step, a multiplication is waiting for the next operand so it can calculate its result, meaning each needs to hold some amount of memory for each step.在每一步,乘法都在等待下一个操作数,以便计算其结果,这意味着每个操作数都需要为每一步保存一定数量的 memory。

With the tail-recursive function, like this:使用尾递归 function,如下所示:

int factorial(int n, int acc)
{
    if (n == 0 || n == 1) return acc;
    return factorial(n - 1, acc * n);
}

the call stack looks like this:调用堆栈如下所示:

factorial(5, 1);
factorial(4, 5);
factorial(3, 20);
factorial(2, 60);
factorial(1, 120);
120

since at each step the function has finished all the calculations it needs to perform, it doesn't need to hold any memory for the results;因为在每一步 function 已经完成了它需要执行的所有计算,它不需要为结果保存任何 memory; each call overwrites the current frame;每次调用都会覆盖当前帧; in other words, it could be rewritten as a loop:换句话说,它可以被重写为一个循环:

int factorial(int n, int acc)
{
    while (true) {
        if (n == 0 || n == 1) return acc;
        acc = acc * n;
        n = n - 1;
    }
}

If the compiler is smart enough, the code for the tail-recursive function gets converted to the equivalent code that this function would generate.如果编译器足够聪明,则尾递归 function 的代码将转换为此 function 将生成的等效代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM