【问题标题】:in this example how do i print the sequence only once? (recursive function)在这个例子中,我如何只打印一次序列? (递归函数)
【发布时间】:2018-11-08 17:07:12
【问题描述】:

只是一个斐波那契算法,我如何打印每一个斐波那契数列而不重复每一步?

递归函数在任何方面都有用吗?我知道它更清晰,但是如果我设置 n = 40,这个简单的算法会有明显的延迟,而迭代的方式是瞬时的。

int fib(int n)
{   
    if (n == 0)
    {
        return 0;
    }
    else if (n == 1)
    {
        return 1;
    }

    return fib(n - 1) + fib(n - 2);
}

【问题讨论】:

  • 也许这个问题和答案会对您非常相似的问题有所启发:stackoverflow.com/q/38215004/1212725
  • @bruceg 仍然不知道什么情况下递归是一个很好的用途,虽然那个帖子确实有帮助,谢谢。
  • 一个朴素的递归解决方案必须计算一次fib(40),但这意味着计算一次fib(39)和一次fib(38)。计算fib(39) 意味着计算fib(38)fib(37) — 因此将计算出两批fib(38)。当然,每一个也计算fib(37)fib(36),所以fib(37)被计算了3次,而且……它很快就积累了很多递归函数调用,这就是为什么递归解决方案比迭代解决方案。否:(天真的)递归斐波那契数列是个坏主意。一个不那么天真的版本会在运行时存储值。
  • 递归只有在学校才有用。在真正的编程中是无用的,一些标准完全禁止它,因为它非常危险且容易出错。它通常速度较慢并消耗大量资源(时间、堆栈空间等)
  • @JonathanLeffler 不那么天真的版本有优势,与迭代方式相同还是更差?

标签: c recursion


【解决方案1】:

您可以通过记忆已经计算的值来轻松优化递归解决方案:

int fib(int n) {
    static int cache[48] = {0}; // should be enough to hold all int fibs
    if(n < 2) return n; // initial conditions
    else if(cache[n]) return cache[n]; // a value already computed and memoized
    else return cache[n] = fib(n - 1) + fib(n - 2); // the largest so far
}

应该加速计算,呃,某个因素。

【讨论】:

  • 一个好主意,但这并不能真正回答 OP 的问题。
  • 确实如此,尽管问题表述不充分。
  • "我如何打印每个斐波那契数列而不重复每一步?"对我来说似乎相当不错。
  • 是的,但是如果您阅读问题正文,则此功能仅计算 F,而将它们打印在其他位置,唯一的问题是fib耗时太长大论据重视。
【解决方案2】:

像 C 这样的命令式语言并不总是能很好地映射到算法的函数定义。

非递归通常更快,因为编译器和处理器都可以更轻松地优化/并行执行执行,并且您不会浪费能源,不必要地推入和弹出堆栈。无论哪种方式,您只需要前两个 fib 值来计算下一个:

void PrintNFibs(unsigned n)
{
    size_t a = 1;
    size_t b = 1;
    size_t sum;
    printf("0\n1\n1\n");
    while ( n-- )
    {
        sum = a + b;
        printf("%zu\n", sum);
        a = b;
        b = sum;
    }
}

根据自身(递归)定义算法是一回事,在 C 中有效地实现它是另一回事。然而,对于像斐波那契这样简单的东西,我不会使用递归,但无论如何这里有一个:

void PrintNFibsR(unsigned n)
{
    static size_t a = 0;
    static size_t b = 1;
    static size_t sum;
    sum = a + b;

    if ( a == 0 )
    {
        printf("0\n1\n");
    }

    printf("%zu\n", sum);
    if ( n > 1 )
    {
        a = b;
        b = sum;
        PrintNFibsR(n - 1);
    }
}

请注意,我们在这里真正要做的只是传递循环计数器。浪费但在技术上是递归的,如果不是真正的功能。编写看起来就像递归斐波那契算法定义的 C 代码的问题在于,它会无缘无故地消耗能量和堆栈空间。您无需预先计算和存储每个值就可以按正确顺序打印值的唯一方法是更改​​算法。

【讨论】:

    猜你喜欢
    • 2016-06-23
    • 1970-01-01
    • 2013-09-23
    • 1970-01-01
    • 1970-01-01
    • 2021-01-26
    • 1970-01-01
    • 1970-01-01
    • 2019-11-06
    相关资源
    最近更新 更多