递归迭代与(recursion versus iteration)

2019-08-18 03:36发布

它是正确的说是无处不在recursion使用的一个for循环可以用吗? 如果递归通常慢是什么技术上的原因永远使用它在for循环迭代?

而如果它总是可以的递归转换成一个for循环是有这样做的拇指方式的规则?

Answer 1:

递归通常要慢得多,因为所有的函数调用必须存储在堆栈中,以允许返回到调用函数。 在许多情况下,内存有被分配并复制到实施范围的隔离。

一些优化,比如尾部调用优化 ,使递归更快,但并不总是可能的,而不是在所有语言中实现。

主要原因使用递归的

  • 这是在许多情况下,更加直观,当它模仿我们的问题的方法
  • 像树木的一些数据结构更容易使用递归探索(或需要在任何情况下栈)

当然,每一个递归模拟为一种循环:这就是CPU将最终做。 和递归本身,更直接,意味着投入堆栈中的函数调用和范围。 但是,改变你的递归算法的一个循环,可能需要大量的工作,使你的代码少维护:为每一个优化的,它应该只尝试当一些分析或证据表明它是必要的。



Answer 2:

它是正确的说是无处不在递归使用的一个for循环可以用吗?

是的,因为在大多数的CPU递归建模与循环和堆栈数据结构。

如果递归通常慢是什么技术原因使用它?

这不是“通常慢”:它是被错误地应用这是较慢的递归。 最重要的是,现代的编译器善于把一些递归到循环,甚至没有要求。

而如果它总是可以的递归转换成一个for循环是有这样做的拇指方式的规则?

写反复解释时,最好的理解算法迭代方案; 写递归算法最好的解释递归程序。

例如,在许多编程语言搜索二叉树,运行快速排序,并解析表达式往往是递归的解释。 这些都是最好的递归编码为好。 在另一方面,计算阶乘和计算斐波那契数更容易在迭代来解释。 使用递归对他们来说就像是用大锤乱打苍蝇:这不是一个好主意,即使大锤做了很好的工作吧+。


+我借用了Dijkstra的“编程的纪律”大锤的比喻。



Answer 3:

题 :

如果递归通常慢是什么技术上的原因永远使用它在for循环迭代?

答:

因为在一些算法是很难迭代求解。 尽量在这两个递归迭代和解决深度优先搜索。 你会得到的想法,这是普通的难以解决的DFS与迭代。

另一件好事尝试:尝试编写合并排序迭代。 它会带你相当长的一段时间。

题 :

它是正确的说是无处不在递归使用的一个for循环可以用吗?

答:

是。 该线程有这个很好的答案。

题 :

而如果它总是可以的递归转换成一个for循环是有这样做的拇指方式的规则?

答:

相信我。 尝试写自己的版本迭代求解深度优先搜索。 你会发现,有些问题更容易解决递归它。

提示:递归是好的,当你解决了可以通过解决的问题分而治之的技术。



Answer 4:

除了是较慢的,递归也可以根据它去有多深导致堆栈溢出错误。



Answer 5:

编写使用迭代等效的方法,我们必须明确地使用堆栈。 该迭代版本,要求其解决方案堆栈的事实表明,这个问题是相当困难的,它可以从递归受益。 作为一般规则,递归最适合于不能用固定的内存量来解决,迭代求解时因此需要堆叠的问题。 话虽如此,递归和迭代可以表现出同样的结果,而他们遵循不同的pattern.To决定哪种方法更好地情况的情况下,最好的做法是选择基于这个问题遵循的模式。

例如,为了找到三角序列的第n个三角数:1 3 6 10 15 ...使用迭代算法来寻找第n个三角数的程序:

使用迭代算法:

//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

使用递归算法:

//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)); 
   }
}


Answer 6:

大部分的答案似乎认为iterative = for loop 。 如果你的循环是不受限制的( 一拉 C,你可以做你想做你的循环计数器等等),那么这是正确的。 如果它是一个真正 for循环(说在Python或大多数函数式语言,你不能手动修改循环计数器),那么它是正确的。

所有(可计算)功能,既可以递归和使用来实现while环(或条件跳转,它们基本上是相同的)。 如果你真的限制自己for loops ,你只会得到的那些功能(原始递归的,如果你的基本操作是合理的)的一个子集。 诚然,这是一个非常大的子集,这恰好包含你可能在实践中encouter每一个功能。

什么是更重要的是,很多功能都是非常容易实现递归和非常难以实现迭代(手动管理您的调用堆栈不计)。



Answer 7:

我似乎记得我的计算机科学教授说,早在一天,对具有递归解决所有的问题也有反复的解决方案。 他说,一个递归的解决方案通常是比较慢,但是当他们更容易推理和代码比迭代的解决方案,他们经常使用。

然而,在更先进的解决方案,递归的情况下,我不相信这将始终能够使用简单的实现他们for循环。



Answer 8:

是的, 说通过Thanakron Tandavas ,

递归是好当你要解决可以通过分而治之的技术来解决的问题。

例如:河内塔

  1. N次响铃的尺寸增大
  2. 3个极
  3. 环开始堆放在极1.目标是,使它们堆积在杆3移动环......但
    • 只能在一次移动一环。
    • 不能把大环上的更小的顶部。
  4. 迭代的解决方案是“强大而又难看”; 递归的解决办法是“优雅”。


Answer 9:

很多很好的理由已经给出,我想与大家分享一个多点。 有些问题用递归精美解决,而只能通过递归来解决。 样品的例子是:

打印数组的所有值,但数组的项目可能是阵列为好。 有可能被嵌套数组作为好,但我们不能确定嵌套数组的深度。

一个美丽的解决办法是这样的:

<?php
  function print_all_items($array){

       foreach($array as $key=>$value){
           if(is_array($value)) { 
             print_all_items($value);
           }
           else{
             echo "$key => $value <br/>";
           }
       }
  }

$array = array("first" => "first value",  
              "second" => "second value",  
              "third" => "third value",  
               "fourth"=>array(1,2,3,4,5),
              "fifth"=>array(
                       "second array 1",
                       "second array 2",
                       "second array 3",
                       array(
                           "third array 1",
                           "third array 2",
                           "third array 3",
                           )
                       ),
              );

print_all_items($array);

输出:

first => first value 
second => second value 
third => third value 
0 => 1 
1 => 2 
2 => 3 
3 => 4 
4 => 5 
0 => second array 1 
1 => second array 2 
2 => second array 3 
0 => third array 1 
1 => third array 2 
2 => third array 3 

现在,这样的问题不能被解决的iterative approach ,因为问题的本质要求动态的解决方案。



Answer 10:

递归+记忆可能会导致更有效的解决方案与纯迭代的方法比较,如检查: http://jsperf.com/fibonacci-memoized-vs-iterative-for-large-n



Answer 11:

答案很简单:这种交易递归更快,对循环占用更少的内存在几乎所有情况。 但是通常有办法改变for循环或递归使其运行速度更快



文章来源: recursion versus iteration