使用递归函数是否可能导致堆栈溢出?
这个功能有问题吗?
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(阶乘(q),阶乘(qp))可以被取消。 我们只需要计算 qx (q-1) ... x (q -k +1)。
还有其他问题吗?
欢迎任何评论。
谢谢
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.
max(factorial(q), factorial(q-p)) can be cancelled out.
We only need to compute q x (q-1) ... x (q -k +1).
Are there other problems ?
Any comments are welcome.
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
堆栈溢出不是代码的主要问题...如果 m 非常大,您将得到 整数溢出 在出现堆栈溢出之前。
如果您希望它适用于大于 12 的 m(取决于您平台上的
unsigned long
的大小),您需要使用某种 Bignum 类型。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.
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).它不是以尾递归形式编写的,因此即使编译器支持适当的尾调用优化,您也不会受益。
It is not written in tail recursive form so even if the compiler supports proper tail call optimization, you won't get the benefit.
该函数实际上可能会导致堆栈溢出(每个递归级别都会消耗一点堆栈,直到全部消耗完为止)。
正如其他人提到的,您可以将递归函数转换为循环,在本例中这很简单,或者您可以修改递归以允许尾部调用优化(让编译器将递归转换为循环)。
正因为如此,要转变为尾递归调用,函数的最后一条语句必须是返回递归调用得到的结果。您的代码无法被优化掉,因为您的 return 语句包含
m*factorial(n-1)
,也就是说,您不返回递归的值,而是在返回之前对其进行实际操作。使其尾递归的转换需要将乘法下推到递归调用,这通常作为保留临时结果的额外参数执行:
但话又说回来,对于该特定问题,有效的迭代解决方案可能更容易得到正确的结果。只需将累积结果保存在临时变量中并循环,直到参数减少到 1。
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.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:
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.