【问题标题】:Which is more efficient recursion or loops?哪个是更有效的递归或循环?
【发布时间】:2013-09-19 10:19:02
【问题描述】:

我很好奇哪个对迭代更有效。我正在使用一个将字符串解析为列表。递归是更高效还是循环?内存效率更高吗?通过循环,我指的是 for、for each、do while、while 和任何其他类型。在这些循环中哪个更有效?还是他们都一样?只是好奇。

【问题讨论】:

  • 递归效率不高。
  • 你的琴弦会分解成无数个部分吗?如果没有,那么“效率”根本就没有区别。
  • 只是为了确保:您是否将解析确定为应用程序的瓶颈?如果没有,您可以忽略任何替代方法可能带来的任何效率提升。一般规则是专注于可读性和可维护性;只解决性能成为问题的性能。
  • 这能回答你的问题吗? Efficiency: recursion vs loop

标签: java loops recursion performance


【解决方案1】:

迭代通常会更有效率。递归需要更多内存(设置堆栈帧)和时间(相同)。但是,如果您可以设置尾递归,编译器几乎肯定会将其编译为迭代或类似的东西,从而为您提供递归的可读性优势,以及迭代方法的性能。

在某些情况下,迭代解决方案将通过本质上维护您自己的堆栈来实现,因此差异可能很小。

更多详情请见Is recursion ever faster than looping?

【讨论】:

  • 我的错,我错过了Java标签。
【解决方案2】:

某些情况更适合递归……而其他情况更适合简单迭代。例如,导航目录优于递归。其他树结构也一样。但是递归使用更多的内存。对于迭代简单列表(如字符串),迭代(循环)更有效。

【讨论】:

    【解决方案3】:

    您无法对此作出一般性陈述。这取决于循环在做什么、如何编码……以及 JIT 编译器对其进行优化的能力如何。它还可以影响循环迭代的列表类型。递归也是如此。

    要获得可靠的答案,您需要逐个检查各种替代方案,并(仔细!)对您的 Java 平台上的特定示例进行基准测试。

    Java 中的递归存在一个问题,即每一级递归都需要一个堆栈帧,而 Java 堆栈的大小是有限的。如果您必须递归太深,您的算法将因StackOverflowError 而崩溃。 (当前一代 Java 平台没有实现尾调用优化。)

    您还希望避免在 LinkedList 上执行基于索引的迭代(例如 for i = 0 to size - 1),因为这会给您带来 O(N^2) 行为。


    幸运的是,不同类型的 Java 循环在性能上的差异通常并没有产生足够的影响。因此(以堆栈深度问题为模,以及选择正确的List 类的问题),您可以放心地将性能留给“以后”...并在必要时处理它 做性能优化。

    【讨论】:

      【解决方案4】:

      在我看来,对您的问题的最佳回答是“视情况而定”:

      平均而言,在搜索 SORTED 集合时,递归要快得多,因为您可以使用“分而治之”之类的算法(在这种情况下,将集合分成两部分并将元素可能所在的一半发送到下一步递归。当元素被找到或不包含在集合中时,递归停止。

      尽管如此,在大多数情况下,循环比递归更有效,因为在不同的递归级别下降时,CPU 将变量保留在堆栈中,这基本上会填满它。循环仅在堆栈中使用恒定数量的空间(通常,但有例外)。例如,如果您使用递归算法计算斐波那契数列,则在斐波那契(30)之后需要数年才能得到结果。该序列可以通过记忆(基本上使用循环)来计算。

      要记住的一点是,递归比循环更容易理解,也更容易帮助解决问题。许多基于循环的问题解决方案都是从递归算法(分治法)开始的,该算法在循环算法(记忆化)中得到优化。我上了这门课,真的很有趣。

      希望我能帮上忙。

      问候。

      【讨论】:

        【解决方案5】:

        在我的选择中,循环更好,递归会有函数调用跟踪,这会占用更多的内存。再次取决于功能

        【讨论】:

          【解决方案6】:

          我同意其他发帖者的观点,因为这实际上取决于您要解决的问题。我个人的偏好是通常避免递归,因为与迭代相比,它可能更难维护和调试,并且取决于实现者或维护者的技能(谁是较弱的环节)。然而,没有提到的一项是使用一些新的 Java 线程功能(例如 ForkJoinPool),可以很容易地将递归解决方案制成多线程解决方案。并不是说 Java 中的线程很困难,但是如果在线程中分配工作负载成为一个问题并且这种类型的功能很有用,那么在设计系统时需要考虑这一点。

          【讨论】:

            【解决方案7】:

            我创建了两个衡量递归与循环性能的微基准。他们都在随机数据集上执行计算,以避免 JIT 作弊。

            在第一种情况下,我计算随机整数矩阵中单元格的总和。当矩阵的一边等于 60 时,递归比循环慢 10 倍。

            在第二种情况下,我通过生成斐波那契数来比较递归与递归仿真。递归仿真是 GC 友好的 - 计算期间没有内存分配。在这种情况下,递归在“较小”情况下快 2 倍,在繁重计算下快 5 倍。

            所以底线是 Java 中的递归非常有效,虽然不像循环那样有效。

            Environment:
            OS: Windows 8 6.2, Core i5
            JVM: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 23.25-b01
            

            来源地址github

            【讨论】:

              猜你喜欢
              • 2016-05-25
              • 2017-03-11
              • 2011-11-04
              • 2017-08-11
              • 1970-01-01
              • 2019-10-13
              • 2011-03-02
              • 1970-01-01
              • 2011-01-07
              相关资源
              最近更新 更多