是否可以通过使用递归函数使堆栈溢出?

时间:2011-10-17 21:31:06

标签: c++ c recursion stack stack-overflow

这个功能有一些问题吗?

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

如果我添加其他功能:

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

这个myCombina()效率不高,因为应该取消最大公约数以找到组合。

max(factorial(q),factorial(q-p))可以抵消。 我们只需要计算q x(q-1)... x(q -k +1)。

还有其他问题吗?

欢迎任何评论。

由于

3 个答案:

答案 0 :(得分:8)

  

如果m非常大,则可能有堆栈溢出。

堆栈溢出不是代码的主要问题...如果m非常大,在堆栈溢出之前会得到integer overflow

如果您希望这种方法适用于大于12的m(取决于平台上unsigned long的大小),则需要使用某种Bignum类型。

答案 1 :(得分:2)

它不是以尾递归形式编写的,所以即使编译器支持正确的尾调用优化,也不会得到好处。

答案 2 :(得分:2)

该函数实际上可能导致堆栈溢出(每个递归级别将占用堆栈的一小部分,直到它被消耗掉)。

正如其他人所提到的,你可以将递归函数转换为循环,在这种情况下可以很简单,或者你可以修改递归以允许尾调用优化(让编译器将递归转换为循环)

只是为了它,要转换为尾递归调用,函数的最后一个语句必须是一个返回,其结果来自递归调用。您的代码无法进行优化,因为您的return语句包含m*factorial(n-1),也就是说,您不返回递归的值,而是在返回之前对其进行操作。

使尾部递归的转换需要将乘法推送到递归调用,这通常作为保留临时结果的额外参数执行:

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
}

但话又说回来,对于那个特定的问题,一个有效的迭代解决方案可能更容易做对。只需将累积结果保存在临时变量中并循环,直到参数减少为1。