迭代和递归有啥区别?

Posted

技术标签:

【中文标题】迭代和递归有啥区别?【英文标题】:What is the difference between iteration and recursion?迭代和递归有什么区别? 【发布时间】:2013-11-16 15:59:37 【问题描述】:

iterationrecursion 之间有什么区别以及为什么/何时更好:

while (true) 
    // Iterating

private void recursion() 
    if (true)
        recursion(); // Recursing

    return;

我看到了很多 recursive 的实现,虽然它可以在一个简单的循环中轻松完成。

【问题讨论】:

函数式语言倾向于鼓励递归。它在 C 语言中不太常见,但仍然非常有用和强大,并且需要解决一些问题。迭代通常更快,一些编译器实际上会将某些递归代码转换为迭代。递归通常比迭代更优雅。 Recursion or Iteration?的可能重复 作者,请在 SO 学习 Google 并使用搜索。这个问题必须关闭并删除为 101 重复。我已经可以看到大量的复​​制/粘贴答案了。 【参考方案1】:

递归和同一算法的迭代版本之间有两个主要区别。

首先,有时理解递归算法几乎比理解迭代算法更好(至少如果你是经验丰富的程序员)所以它确实增加了表达性,在某些情况下增加了可读性(它也可能导致完全相反在其他情况下)

表达能力对编程语言来说意义重大,能够用 5 行而不是 20 行编写相同的代码是一个巨大的问题。

不利的一面是,它会降低代码的性能。递归函数必须将函数记录保存在内存中,并从一个内存地址跳转到另一个内存地址以被调用以传递参数和返回值。这使他们的表现非常糟糕。

总结:

迭代算法 = 性能快速但难以编写(有时也难以阅读)

递归算法 = 编写速度快,但性能不佳(有时也更容易理解)

举个例子:

public static long fib(long n) 
    if (n <= 1) return n;
    else return fib(n-1) + fib(n-2);

    if ((n == 1) || (n == 2)) 
        return 1;
     else 
        long prev = 1, current = 1, next = 0;
        for (long i = 3; i <= n; i++) 
            next = prev + current;
            prev = current;
            current = next;
        
        return next;
    

来源:

http://www.csd.uwo.ca/Courses/CS1027a/code/FibonacciDemo.java

【讨论】:

有趣,你的例子为我做了,它清除了我对它们的模糊想法。 但迭代可以更完善... int cur=1,prev=0; while (--n) int next = cur+prev; prev = cur; cur = next; return cur; @SHR 有点正确,如果没有人会维护该代码。但递归版本仍然更短。 很好的解释,需要补充的一点是,根据语言和编译器的不同,优化递归算法的性能可以接近或相等,同时在很大程度上保持可读性。例如,计算fib(n-1) + fib(n-2) 会非常昂贵,但可以通过接受前两个值作为输入的尾调用辅助函数来实现。【参考方案2】:

递归和迭代的主要区别在于内存使用。

因为每个递归调用都需要堆栈帧上的空间,从而导致内存开销。

让我举个例子。想象一下,在一种情况下,您忘记为递归函数编写基本情况,导致无休止的递归调用,而在另一种情况下,您编写了一个无限循环。

由于每个递归函数都会分配新的内存空间,所以在第一种情况下,您的代码会给出堆栈溢出异常,但在第二种情况下,它将永远运行。

因此,让您的迭代代码比使用递归更易于理解。

【讨论】:

非常真实,从没想过,+1! 内存使用不是那么简单,因为尾调用优化现在相当标准。许多递归算法自然包含像return recurse(arg) 这样的行,其他的可以很容易地重写以使用这种形式。当这样完成时,返回路径只是爬上每次返回的堆栈。除了第一个函数调用之外,您可以通过不使用堆栈来优化这一点 - 立即返回并且每次递归不使用任何额外的内存。【参考方案3】:

它们是做同一件事的不同方法。所有递归实现都可以通过一个(或多个)循环来完成,反之亦然。它更多的是关于它背后的逻辑,一种思考它的方式。阶乘,虽然不是最好的例子,但 n * (n-1)! 所以递归使用它是有意义的。

【讨论】:

【参考方案4】:

递归和迭代是思考解决方案的不同方式。 很难深入解释整个范围的差异。在您的示例代码中,您已经展示了差异。 递归函数是调用自身的函数,而迭代函数是循环某个代码块的函数。 这里有一些文章可以帮助您更好地理解它们: Recursion wiki

Iteration wiki

CodeProject SO #1

SO #2

【讨论】:

【参考方案5】:

它们可以互换使用来解决不同的问题。本质上,您可以迭代地编写递归函数,反之亦然。

迭代可能会提高程序的性能。而递归可能会给出更直观和优雅的结果。您可以根据自己的喜好选择其中一个!

【讨论】:

【参考方案6】:

递归函数通过调用自身直到满足某个条件的过程来工作,而迭代使用循环控制结构(例如while、do while、for)来重复一段代码直到满足某个条件。

递归示例:

int rec_func(int u, int k) 
  if (k == 0)
    return u;
  return rec_func(u * k, k - 1);

迭代示例:

int ite_func(int u, int k) 
  while (k != 0) 
    u = u * k;
    k = k - 1;
  
  return u;
 

IMO 之间唯一真正的区别是编译差异。

【讨论】:

不,不是真的。在上面的代码示例中,一个会无限循环,一个会在堆栈已满时导致错误。【参考方案7】:

理论上,您始终可以在迭代和递归之间切换。但是,至少在 C/C++/C#/Java 的情况下,编译器会为您提供一些支持,这可能会使解决方案更加优雅,尤其是当您之前不知道循环的数量时。

最好的例子是列出文件夹中的所有文件及其后代。如果有多个包含子文件夹的子文件夹,通常在迭代模式下,您需要一个堆栈来保存您需要分析的所有文件夹。在递归的情况下,堆栈已经由编译器提供,解决方案更加优雅。

【讨论】:

【参考方案8】:

递归和迭代的区别

递归

    递归函数 - 是部分由自身定义的函数 递归使用选择结构 如果递归步骤不能以收敛于某些条件(基本情况)的方式减少问题,则会发生无限递归 识别基本情况时递归终止 由于维护堆栈的开销,递归通常比迭代慢 递归比迭代使用更多内存 无限递归会导致系统崩溃 递归使代码更小

迭代

    迭代指令 - 是基于循环的过程重复 迭代使用重复结构 如果循环条件测试永远不会为假,则会在迭代中发生无限循环 循环条件失败时迭代终止 迭代不使用堆栈,因此比递归更快 迭代消耗更少的内存 无限循环重复使用 CPU 周期 迭代使代码更长

数据取自here。

【讨论】:

以上是关于迭代和递归有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

价值迭代和策略迭代有啥区别? [关闭]

迭代和遍历有啥区别?

返回函数调用与仅在递归期间再次调用函数有啥区别?

使用 foreach 或在 Perl 中迭代文件有啥区别?

递归和迭代的区别?

open() 的缓冲参数和迭代文件时使用的硬编码预读缓冲区大小有啥区别?