recursion与迭代

是否正确地说,无处不在recursion使用for循环可以使用? 如果recursion通常比较慢,那么循环迭代使用它的技术原因是什么?

如果总是有可能将recursion转换为for循环,那么有一种经验法则可以做到这一点?

recursion通常要慢得多,因为所有的函数调用都必须存储在一个堆栈中以允许返callback用者函数。 在很多情况下,必须分配和复制内存以实现范围隔离。

一些优化,如尾调用优化 ,使recursion更快,但并不总是可能的,并没有在所有的语言实现。

使用recursion的主要原因是

  • 当它模仿我们的问题的方法时,在许多情况下它更直观
  • 像树这样的数据结构更容易使用recursion进行探索(或者在任何情况下都需要堆栈)

当然,每个recursion可以build模为一种循环:这就是CPU最终要做的。 而recursion本身更直接,意味着把函数调用和范围放在一个堆栈中。 但是,将recursionalgorithm改为循环algorithm可能需要很多工作,并且使代码更易于维护:对于每个优化,只有在某些分析或证据显示有必要时才应尝试。

是否正确地说,无处不在recursion使用for循环可以使用?

是的,因为大多数CPU的recursion是用循环和堆栈数据结构build模的。

而如果recursion通常较慢,使用它的技术原因是什么?

它不是“通常较慢”:它是recursion,应用不正确,这是慢的。 最重要的是,现代编译器擅长将一些recursion转换为循环,甚至不问。

如果总是有可能将recursion转换为for循环,那么有一种经验法则可以做到这一点?

编写迭代程序迭代地解释时最好理解的algorithm; 写recursion程序最好recursion地解释。

例如,在许多编程语言中search二叉树,运行快速sorting和parsingexpression式通常是recursion地解释的。 这些也是最好的recursion编码。 另一方面,计算阶乘和斐波那契数的计算在迭代方面更容易解释。 对他们使用recursion就像用大锤扑苍蝇一样:即使大锤做得很好,这也不是一个好主意。


+我从迪克斯特拉的“编程学科”中借用了大锤的类比。

题 :

如果recursion通常比较慢,那么循环迭代使用它的技术原因是什么?

答:

因为在一些algorithm中很难迭代求解。 尝试以recursion和迭代方式解决深度优先search。 你会得到这样的想法,很难用迭代来解决DFS。

另一个好的尝试:尝试写迭代合并sorting。 这将花费您相当长的一段时间。

题 :

是否正确地说,无处不在recursion使用for循环可以使用?

答:

是。 这个线程对此有一个很好的答案。

题 :

如果总是有可能将recursion转换为for循环,那么有一种经验法则可以做到这一点?

答:

相信我。 尝试编写自己的版本来迭代地解决深度优先search。 你会注意到一些问题更容易recursion解决。

提示:当你解决一个可以通过分治技术解决的问题时,recursion是很好的。

除了速度较慢之外,recursion也可能导致堆栈溢出错误,这取决于它的深度。

要使用迭代编写等价的方法,我们必须明确地使用一个堆栈。 迭代版本需要一个堆栈来解决这个问题的事实表明,这个问题已经足够困难,从而可以从recursion中受益。 作为一般规则,recursion最适合用固定数量的内存无法解决的问题,因此迭代求解时需要一个堆栈。 话虽如此,recursion和迭代在遵循不同模式的情况下可以performance出相同的结果。要确定哪种方法更好地工作,最好的做法是根据问题所遵循的模式进行select。

例如,查找三angular形序列的第n个三angular形:1 3 6 10 15 …使用迭代algorithmfind第n个三angular形的程序:

使用迭代algorithm:

 //Triangular.java import java.util.*; class Triangular { public static int iterativeTriangular(int n) { int sum = 0; for (int i = 1; i <= n; i ++) sum += i; return sum; } public static void main(String args[]) { Scanner stdin = new Scanner(System.in); System.out.print("Please enter a number: "); int n = stdin.nextInt(); System.out.println("The " + n + "-th triangular number is: " + iterativeTriangular(n)); } }//enter code here 

使用recursionalgorithm:

 //Triangular.java import java.util.*; class Triangular { public static int recursiveTriangular(int n) { if (n == 1) return 1; return recursiveTriangular(n-1) + n; } public static void main(String args[]) { Scanner stdin = new Scanner(System.in); System.out.print("Please enter a number: "); int n = stdin.nextInt(); System.out.println("The " + n + "-th triangular number is: " + recursiveTriangular(n)); } } 

我似乎记得我的计算机科学教授当天回来说,所有具有recursion解决scheme的问题都有迭代解决scheme。 他说recursion解决scheme通常比较慢,但是当它们比迭代解决scheme更容易推理和编码时,它们经常被使用。

但是,在更高级的recursion解决scheme的情况下,我不相信它总是能够使用简单的for循环来实现它们。

大多数的答案似乎假设iterative = for loop 。 如果你的for循环是不受限制的( 一个lac ,你可以用你的循环计数器做任何你想要的),那么这是正确的。 如果它是一个真正 for循环(比如说在Python或者大多数函数式语言中你不能手动修改循环计数器),那么它是正确的。

所有(可计算)函数都可以recursion实现,也可以使用while循环(或条件跳转,基本上是相同的)。 如果你真的把自己限制for loops ,你只会得到这些函数的一个子集(原始的recursion的,如果你的基本操作是合理的)。 当然,这是一个非常大的子集,它包含了每一个你可能在实践中遇到的函数。

更重要的是,很多函数很容易recursion实现,很难迭代实现(手动pipe理你的调用堆栈不计数)。

如上述答案所述,recursion与迭代相比较慢,但是recursion在某些情况下是合适的,并且迭代方法对于某些情况是好的。 然而,在selectrecursion之前,最好分析一下你要解决的问题。 最重要的是给予一些大的投入来分析。 我希望下面的链接会给你更清晰的这个, http://knowledge-cess.com/recursion-vs-iteration-an-analysis-fibonacci-and-factorial/

是的,正如Thanakron Tandavas所说 ,

当你解决一个可以通过分治技术解决的问题时,recursion是很好的。

例如:河内的塔

  1. N环越来越大
  2. 3极
  3. 戒指开始堆积在杆1上。目标是移动戒指,使它们堆叠在杆3上
    • 一次只能移动一个环。
    • 不能把较大的戒指放在较小的顶部。
  4. 迭代解决scheme“function强大但难看”; recursion解决scheme是“优雅”的。

与单纯的迭代方法相比,recursion+记忆可能会导致更高效的解决scheme,例如:检查: http : //jsperf.com/fibonacci-memoized-vs-iterative-for-large-n

简短的回答:权衡是recursion更快,循环几乎在所有情况下占用较less的内存。 但是通常有更改for循环或recursion的方法来使其运行更快