哪个更有效的递归或循环?

时间:2013-09-15 01:44:00

标签: java loops recursion performance

我很好奇哪种迭代效率更高。我正在使用一个解析一个字符串解析为List。递归更有效率CPU还是循环?要么更高效的内存?通过循环,我指的是,为每个,做,while,和任何其他类型。这些循环中哪些更有效?或者他们都是平等的?好奇。

7 个答案:

答案 0 :(得分:8)

你无法就此作出一般性陈述。这取决于循环的作用,编码方式以及JIT编译器如何优化它。它也可以改变循环迭代的列表类型。递归也是如此。

要获得可靠的答案,您需要根据具体情况检查各种备选方案,并(仔细!)对Java平台上的特定示例进行基准测试。

Java中的递归存在每个递归级别都需要堆栈帧的问题,并且Java堆栈具有有限的大小。如果你必须过于递归,你的算法会因StackOverflowError而崩溃。 (当前一代Java平台不实现尾调用优化。)

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


幸运的是,不同类型的Java循环通常的性能差异并没有产生足够的差异。所以(以堆积深度问题为模,以及选择正确的List类的问题),您可以安全地将性能保持为“以后”......并且如果它只是处理它并且只处理如果它有必要进行性能优化。

答案 1 :(得分:1)

迭代通常会更有效率。递归需要更多内存(设置堆栈帧)和时间(相同)。但是,如果你可以设置尾递归,编译器几乎肯定会把它编译成迭代,或者变成类似的东西,给你递归的可读性优势,以及迭代方法的性能。

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

有关详细信息,请参阅Is recursion ever faster than looping?

答案 2 :(得分:1)

根据我的说法,你问题的最佳答案是“它取决于”:

平均而言,在搜索SORTED集合时递归速度要快得多,因为您可以使用“Divide and Conquer”等算法(在这种情况下,将集合分为两部分,并将元素发送到下一步的一半)递归。当元素被找到或未包含在集合中时,递归停止。

对于大多数情况,循环比递归更有效,因为简单的事实是,在不同的递归级别中,CPU会将变量保留在堆栈中,这基本上会填满它。循环仅在堆栈中使用恒定数量的空间(通常,但例外情况适用)。例如,如果您使用递归算法计算Fibbonacci序列,则需要数年时间才能在Fibonnacci(30)之后得到结果。可以使用Memoization(基本上使用循环)计算该序列。

要记住的一件事是递归更容易理解,并且比循环更容易解决问题。许多基于循环的问题解决方案都是从循环算法(Memoization)中优化的递归算法(Divide and Conquer)开始的。我参加了这个课程的课程,这真的很有趣。

希望我帮助过。

问候。

答案 3 :(得分:0)

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

答案 4 :(得分:0)

在我的选项中,循环更好,递归将具有函数调用跟踪,这将占用更多内存。而且它取决于功能

答案 5 :(得分:0)

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

答案 6 :(得分:0)

我创建了两个微基准测试来测量递归与循环性能。他们都对随机数据集进行计算,以避免JIT作弊。

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

在第二种情况下,我通过生成Fibonacci数来比较递归与递归仿真。递归仿真是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