使用递归可以解决哪些问题?

时间:2017-07-29 19:47:37

标签: php algorithm loops recursion

今天我在php中使用递归制作了一个方法并对它感兴趣。什么问题实际上可以递归解决?对于我们可以使用递归的东西?

我开始在网上搜索并搜索和搜索,但我找不到任何东西。

所以我在问,我怎样才能使用递归?

有一些限制吗?我们不能用递归但用标准循环做的事情吗?我想知道我是否可以在我的代码中正常使用现在的递归。

2 个答案:

答案 0 :(得分:4)

使用递归我们能做些什么?

解决递归问题。父子问题,每个孩子都可以再次成为父母,这是最常见的问题。

HasAttachment

是否有一些限制?

是。 PHP(和其他编程语言)跟踪哪些代码调用哪个函数,因此它知道函数返回后的继续。这称为function doSomethingWithNode($node) { // Do something with $node // Loop over all childs, and run this code for those childs too, and for those childs, and for those childs, and ... foreach($node->getChilds() as $child) { doSomethingWithNode($child); } } doSomethingWithNode($rootNode); 。向call stack添加新条目将花费一些内存和一些时间。当你有很多(数百万)次迭代时,主要是第一个CAN导致问题。

根据您的安装,call stack甚至可能会受到限制。默认情况下它不是。通过安装call stack - 扩展,它最多可以提供100个嵌套调用(默认情况下,可以在配置中更改)。在这些设置中,它将导致致命错误(example)。

我们可以通过标准循环来处理递归但我们能做什么?我想知道我是否可以在我的代码中正常使用现在的递归

由于上述限制,应谨慎使用递归。当您可以使用普通while或for循环解决它时:使用正常循环。大多数情况下,它将使代码更容易阅读。

当您关心可移植性时(例如编写开源项目时),您可能想要考虑xdebug用户。

答案 1 :(得分:3)

通过任何数据结构迭代的每种类型都可以通过递归来完成。实际上,您可以将forwhiledo whileforeach等每个循环结构替换为简单的递归:

function factorial($n) {
  $result = $n < 0 ? -1 : 1;
  for($i = abs($n), $i > 1; $i--) {
    $result *= $i; 
  }
  return $result;
}

可写:

function factorial($n) {
  $forHelper = function($result, $i) {
    return $i === 1 ? $result : $forHelper($result * $i, $i - 1);
  }
  return $forHelper($n < 0 ? -1 : 1, abs($n)); 
}

这称为尾递归。在某些语言中,上面两个生成非常相似的运行时代码,但不是PHP。它为每次调用使用一些内存。对我来说,两者都具有相同的可读性,但我敢打赌,大多数程序员会发现循环更容易,特别是当它嵌套时。

使用递归而不是迭代,迭代图形或树的某些算法将具有更简单的版本:

function treeDepth($node) {
  if( $node === null ) {
    return 0;
  } else {
    return 1 + max(treeDepth($node->left), treeDepth($node->right));
  }
}

这里的迭代解决方案需要某种方式来跟踪它需要访问的位置,因此您正在做一些由递归版本自动处理的内务处理。

function treeDepth($node) {
  $max = 0;
  $backtrack = [[0, $node]];
  while( count($backtrack) ) {
    list($depth, $node) = array_pop($backtrack); 
    while($node !== null) {
      array_push($backtrack, [++$depth, $node->right]);
      $node = $node->left; 
    }
    $max = max($max, $depth);
  }
  return $max; 
}

限制取决于语言。在PHP中,它为每个未分配给简单循环的调用帧分配一些内存。节点遍历始终使用内存,因为该进程本质上是递归的。

最终,您应该以尽可能清晰的方式编写代码,而不必考虑优化。使用最清晰的循环结构和最清晰的递归。只有当您真正遇到性能问题时,才应该分析和重写使用最多时间的部分。我用它来保留原始代码作为注释,如果它很短并记录在更复杂的迭代版本中实际发生的事情。在PHP中,函数调用本身很昂贵。