Recursion or Iteration?

2018-12-31 17:03发布

Is there a performance hit if we use loop instead of recursion or vice versa in algorithms where both can serve the same purpose? Eg : Check if given string is palindrome. I have seen many programmers using recursion as a means to show off when a simple iteration algorithm can fit the bill. Does the compiler play a vital role in deciding what to use?

28条回答
弹指情弦暗扣
2楼-- · 2018-12-31 17:39

it depends on "recursion depth". it depends on how much the function call overhead will influence the total execution time.

For example, calculating the classical factorial in a recursive way is very inefficient due to: - risk of data overflowing - risk of stack overflowing - function call overhead occupy 80% of execution time

while developing a min-max algorithm for position analysis in the game of chess that will analyze subsequent N moves can be implemented in recursion over the "analysis depth" (as I'm doing ^_^)

查看更多
与风俱净
3楼-- · 2018-12-31 17:40

Typically, one would expect the performance penalty to lie in the other direction. Recursive calls can lead to the construction of extra stack frames; the penalty for this varies. Also, in some languages like Python (more correctly, in some implementations of some languages...), you can run into stack limits rather easily for tasks you might specify recursively, such as finding the maximum value in a tree data structure. In these cases, you really want to stick with loops.

Writing good recursive functions can reduce the performance penalty somewhat, assuming you have a compiler that optimizes tail recursions, etc. (Also double check to make sure that the function really is tail recursive---it's one of those things that many people make mistakes on.)

Apart from "edge" cases (high performance computing, very large recursion depth, etc.), it's preferable to adopt the approach that most clearly expresses your intent, is well-designed, and is maintainable. Optimize only after identifying a need.

查看更多
十年一品温如言
4楼-- · 2018-12-31 17:40

I would think in (non tail) recursion there would be a performance hit for allocating a new stack etc every time the function is called (dependent on language of course).

查看更多
墨雨无痕
5楼-- · 2018-12-31 17:42

Recursion is better than iteration for problems that can be broken down into multiple, smaller pieces.

For example, to make a recursive Fibonnaci algorithm, you break down fib(n) into fib(n-1) and fib(n-2) and compute both parts. Iteration only allows you to repeat a single function over and over again.

However, Fibonacci is actually a broken example and I think iteration is actually more efficient. Notice that fib(n) = fib(n-1) + fib(n-2) and fib(n-1) = fib(n-2) + fib(n-3). fib(n-1) gets calculated twice!

A better example is a recursive algorithm for a tree. The problem of analyzing the parent node can be broken down into multiple smaller problems of analyzing each child node. Unlike the Fibonacci example, the smaller problems are independent of each other.

So yeah - recursion is better than iteration for problems that can be broken down into multiple, smaller, independent, similar problems.

查看更多
闭嘴吧你
6楼-- · 2018-12-31 17:43

Recursion is very useful is some situations. For example consider the code for finding the factorial

int factorial ( int input )
{
  int x, fact = 1;
  for ( x = input; x > 1; x--)
     fact *= x;
  return fact;
}

Now consider it by using the recursive function

int factorial ( int input )
{
  if (input == 0)
  {
     return 1;
  }
  return input * factorial(input - 1);
}

By observing these two, we can see that recursion is easy to understand. But if it is not used with care it can be so much error prone too. Suppose if we miss if (input == 0), then the code will be executed for some time and ends with usually a stack overflow.

查看更多
旧时光的记忆
7楼-- · 2018-12-31 17:43

As far as I know, Perl does not optimize tail-recursive calls, but you can fake it.

sub f{
  my($l,$r) = @_;

  if( $l >= $r ){
    return $l;
  } else {

    # return f( $l+1, $r );

    @_ = ( $l+1, $r );
    goto &f;

  }
}

When first called it will allocate space on the stack. Then it will change its arguments, and restart the subroutine, without adding anything more to the stack. It will therefore pretend that it never called its self, changing it into an iterative process.

Note that there is no "my @_;" or "local @_;", if you did it would no longer work.

查看更多
登录 后发表回答