简体   繁体   English

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

[英]Which is more efficient recursion or loops?

I am curious which is more efficient for iteration. 我很好奇哪个迭代效率更高。 I am using one to break up a parse a string into a List. 我正在使用一个解析一个字符串解析为List。 Is recursion more CPU efficient or is looping? 递归更有效率CPU还是循环? Is either more memory efficient? 要么更高效的内存? By looping, I am referring to for, for each, do while, while, and any other types. 通过循环,我指的是,为每个,做,while,和任何其他类型。 Out of these loops which are more efficient? 这些循环中哪些更有效? Or are they all equally? 或者他们都是平等的? Just curious. 只是好奇。

You can't make a general statement on that. 你不能就此作出一般性陈述。 It depends on what the loop is doing, how you have coded it ... and how well the JIT compiler is able to optimize it. 这取决于循环的作用,编码方式以及JIT编译器如何优化它。 It can also make a difference what kind of list the loop is iterating over. 它也可以改变循环迭代的列表类型。 The same goes for recursion. 递归也是如此。

To get a reliable answer, you need to examine the various alternatives on a case-by-case basis, and (carefully!) benchmark the specific examples on your Java platfrom. 要获得可靠的答案,您需要根据具体情况检查各种备选方案,并(仔细!)对Java平台上的特定示例进行基准测试。

Recursion in Java has the problem that each level of recursion requires a stack frame, and Java stacks have bounded size. Java中的递归存在每个递归级别都需要堆栈帧的问题,并且Java堆栈具有有限的大小。 If you have to recurse too deeply, your algorithm will crash with a StackOverflowError . 如果你必须过于递归,你的算法将因StackOverflowError而崩溃。 (Current generation Java platforms do not implement tail call optimization.) (当前一代Java平台不实现尾调用优化。)

You also want to avoid doing index-based iteration (eg for i = 0 to size - 1 ) over a LinkedList , because that will give you O(N^2) behaviour. 您还希望避免在LinkedList进行基于索引的迭代(例如, for i = 0 to size - 1 ),因为这将给出O(N^2)行为。


Fortunately, the difference in performance for the different kinds of Java loop usually doesn't make enough difference to matter. 幸运的是,不同类型的Java循环的性能差异通常不会产生足够的差异。 So (modulo the stack depth issue, and the issue of choosing the correct List class), you can safely leave performance to "later" ... and deal with it if-and-only-if it becomes necessary to do performance optimization. 因此(以堆积深度问题为模,以及选择正确的List类的问题),您可以安全地将性能保持为“以后”...... 如果有必要进行性能优化, 则只处理它。

Iteration is generally going to be more efficient. 迭代通常会更有效率。 Recursion requires more memory (to set up stack frames) and time (for the same). 递归需要更多内存(设置堆栈帧)和时间(相同)。 However, if you can set up tail recursion, the compiler will almost certainly compile it into iteration, or into something which is similar, giving you the readability advantage of recursion, with the performance of an iterative method. 但是,如果你可以设置尾递归,编译器几乎肯定会把它编译成迭代,或者编译成类似的东西,给你递归的可读性优势,具有迭代方法的性能。

In some situations an iterative solution will be implemented by essentially maintaining your own stack, so the difference may be minimal. 在某些情况下,迭代解决方案将通过基本维护您自己的堆栈来实现,因此差异可能很小。

See Is recursion ever faster than looping? 请参阅递归比循环更快? for more details. 更多细节。

Well according to me, the best answer to your question would be "it depends" : 那么根据我的说法,你问题的最佳答案是“它取决于”:

On average, recursion is much faster when searching through a SORTED collection because you can use algorithms like "Divide and Conquer" (in this case cutting the collection in two parts and sending the half where the element could be to the next step of the recursion. The recursion stops when the element is either found, or not contained in the collection). 平均而言,在搜索SORTED集合时递归速度要快得多,因为您可以使用“Divide and Conquer”等算法(在这种情况下,将集合分为两部分,并将元素的一半发送到递归的下一步) 。当元素被找到或未包含在集合中时,递归停止。

For most cases though, loops are more efficient than recursion for the simple fact that while going down in the different levels of recursion, the CPU keeps variables in the stack, which basically fills it up. 但是对于大多数情况下,循环比递归更有效,因为简单的事实是,在不同的递归级别中,CPU会将变量保留在堆栈中,这基本上会填充它。 Loops only use a constant amount of room in the stack (generally, but exceptions apply). 循环仅在堆栈中使用恒定数量的空间(通常,但例外情况适用)。 For example, if you were the calculate the Fibbonacci sequence with a recursive algorithm, it would take you years to get a result after Fibonnacci(30). 例如,如果您使用递归算法计算Fibbonacci序列,则需要数年时间才能在Fibonnacci(30)之后得到结果。 That sequence can be calculated with the Memoization (basically using loops). 可以使用Memoization(基本上使用循环)计算该序列。

One thing to remember is that recursion is easier to understand and helps resolve problems much more easily than loops. 要记住的一件事是,递归更容易理解,并且比循环更容易解决问题。 Lots of loop based solutions to problems start with a recursive algorithm (Divide and Conquer) that gets optimised in a loop algorithm (Memoization). 许多基于循环的问题解决方案都是从循环算法(Memoization)中优化的递归算法(Divide and Conquer)开始的。 I took a class on this subject and it was really interesting. 我参加了这个课程的课程,这真的很有趣。

Hope I helped. 希望我帮忙。

Regards. 问候。

certain circumstances are better for recursion...and others for simple iteration. 某些情况更适合递归......而其他情况则适用于简单迭代。 navigating directories for example is superior with recursion. 例如,导航目录优于递归。 Same for other tree structures. 其他树结构也是如此。 However recursion uses more memory. 但是递归会占用更多内存。 For iterating a simple list (like a string) iteration (loops) is more efficient. 对于迭代简单列表(如字符串),迭代(循环)更有效。

In my option, Looping is better, recursion will have the function call trace, which will occupy more memory. 在我的选项中,循环更好,递归将具有函数调用跟踪,这将占用更多的内存。 And again its depends on the functionality 而且它取决于功能

I agree with the other posters in that it really depends on what problem you are solving. 我同意其他海报,因为它确实取决于你正在解决的问题。 My personal preference is to usually avoid recursion as it can be harder to maintain and possibly debug compared to iteration and depending on the skill of the implementor or maintainer, (whover is the weaker link). 我个人的偏好通常是避免递归,因为与迭代相比,它可能更难维护和可能调试,并且取决于实现者或维护者的技能(无论哪个是较弱的链接)。 One item not mentioned however is that with some of the new Java threading feature (eg the ForkJoinPool) a recursive solution can very easily be made into a multi-threaded one. 然而,未提及的一个项目是,使用一些新的Java线程功能(例如ForkJoinPool),递归解决方案可以非常容易地变成多线程解决方案。 Not that threading in Java is difficult, but it is something to consider while designing a system if distributing the workload in threads becomes an issue and this type of feature is useful. 并非Java中的线程化很困难,但如果在线程中分配工作负载成为问题并且这种类型的功能很有用,那么在设计系统时需要考虑这一点。

I have created two microbenchmarks which measure recursion vs loop performance. 我创建了两个微基准测试来测量递归与循环性能。 Both of them perform calculations over a randomized dataset to avoid JIT cheating. 他们都对随机数据集进行计算以避免JIT作弊。

In the first case I calculate a sum of the cells in a randomized integer matrix. 在第一种情况下,我计算随机整数矩阵中的单元格的总和。 With a side of a matrix equal to 60 recursion is 10x slower than loops. 矩阵的一边等于60递归比循环慢10倍。

In the second case I compare recursion vs recursion emulation by generating Fibonacci numbers. 在第二种情况下,我通过生成Fibonacci数来比较递归与递归仿真。 Recursion emulation is GC-friendly - there are no memory allocations during computation. 递归仿真是GC友好的 - 计算期间没有内存分配。 In this case recursion was 2x faster in 'smaller' cases and 5x faster under a heavy computation. 在这种情况下,递归在“较小”情况下快2倍,在繁重计算下快5倍。

So the bottom line is that recursion in Java is very effective, though not effective as loops. 所以底线是Java中的递归非常有效,尽管作为循环不是很有效。

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

Source available at github . 来源于github

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

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