简体   繁体   English

使用递归函数是否可能导致堆栈溢出?

[英]Is it possible to have stack overflow by using recursive function?

This function has some problems ? 这个功能有一些问题吗?

 unsigned long factorial(unsigned long m)
 {
     return (m == 0) ? 1 : m * factorial(m - 1);
 }

If I add another function: 如果我添加另一个功能:

  int myCombina(int q, int p)
  {
      return factorial(q) / ( factorial(q) * factorial(q-p) );
  }

This myCombina() is not efficient because a greatest common divisor should be cancelled in it to find combinatorial. 此myCombina()效率不高,因为应在其中取消最大公约数以找到组合。

max(factorial(q), factorial(qp)) can be cancelled out. 可以取消max(factorial(q),factorial(qp))。 We only need to compute qx (q-1) ... x (q -k +1). 我们只需要计算qx(q-1)... x(q -k +1)。

Are there other problems ? 还有其他问题吗?

Any comments are welcome. 欢迎任何意见。

Thanks 谢谢

if m is very large, it may have stack overflow. 如果m非常大,则可能有堆栈溢出。

A stack overflow is not the main problem with your code... if m is very large you will get an integer overflow before you get a stack overflow. 堆栈溢出不是代码的主要问题...如果m很大,则在得到堆栈溢出之前会得到整数溢出。

You need to use some sort of Bignum type if you want this to work for m larger than about 12 (depending on the size of unsigned long on your platform). 如果要使它在大于约12的m中工作(取决于平台上unsigned long的大小),则需要使用某种Bignum类型。

它不是以尾部递归形式编写的,因此即使编译器支持适当的尾部调用优化,您也不会从中受益。

The function can actually cause an stack overflow (each level of recursion will consume a bit of the stack until it get's all consumed). 该函数实际上可能导致堆栈溢出(每个递归级别将消耗一部分堆栈,直到全部消耗掉)。

As others have mentioned, you can convert the recursive function into a loop, which in this case would be simple, or you can modify the recursion to allow for tail-call optimization (have the compiler transform the recursion into a loop). 正如其他人提到的那样,您可以将递归函数转换为循环,在这种情况下这很简单,或者可以修改递归以进行尾调用优化(已将编译器将递归转换为循环)。

Just for the sake of it, to transform into a tail recursive call, the last statement of the function must be a return with the result obtained from the recursive call. 仅出于此目的,要转换为尾部递归调用,该函数的最后一条语句必须是返回值,其返回值是从递归调用中获得的。 Your code cannot be optimized away because your return statement contains m*factorial(n-1) , that is, you don't return the value of the recursion, but actually operate on it before returning. 您的代码无法优化,因为您的return语句包含m*factorial(n-1) ,也就是说,您没有返回递归的值,而是在返回之前对其进行了实际操作。

The transformation to make it tail recursive require pushing the multiplication down to the recursive call, and that is usually performed as an extra argument that keeps the temporary result: 要使其成为尾递归的转换,需要将乘法向下推到递归调用,并且通常将其作为保留临时结果的额外参数来执行:

unsigned long factorial_tail_recursive( 
                        unsigned long n,           // number to calculate factorial
                        unsigned long temp_result  // accumulated result
                      ) 
{
   return n == 0? tmp_result 
                : factorial_tail_recursive( n-1, n*temp_result );
}

// syntactic sugar to offer the same interface
unsigned long factorial( unsigned long n ) {
   return factorial_tail_recursive( n, 1 );    // accumulated result initialized to 1
}

But then again, for that particular problem an efficient iterative solution is probably easier to get right. 但话又说回来,对于这个特定问题,一个有效的迭代解决方案可能更容易正确。 Just maintain the accumulated result in a temporary variable and loop until the argument is reduced to 1. 只需将累积结果保留在一个临时变量中并循环,直到参数减小为1。

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

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