编写了我认为是一个很好的算法的代码,用于使用递归查找大数的最大素因子。我的程序崩溃时,任何大于4的数字都会分配给变量huge_number。我不善于递归,并且赋值不允许任何类型的循环。
#include <stdio.h>
long long prime_factor(int n, long long huge_number);
int main (void)
{
int n = 2;
long long huge_number = 60085147514;
long long largest_prime = 0;
largest_prime = prime_factor(n, huge_number);
printf("%ld\n", largest_prime);
return 0;
}
long long prime_factor (int n, long long huge_number)
{
if (huge_number / n == 1)
return huge_number;
else if (huge_number % n == 0)
return prime_factor (n, huge_number / n);
else
return prime_factor (n++, huge_number);
}
任何关于它为什么会崩溃以及如何改进它的信息将非常感激。
答案 0 :(得分:1)
您的意思是n+1
而不是n++
。 使用后n++
递增n
,因此递归调用获得原始值n
。
答案 1 :(得分:1)
你正在溢出堆栈,因为n ++后递增值,使用与当前调用相同的值进行递归调用。
答案 2 :(得分:0)
即使解决使用后递增的问题以使递归永远持续,这也不适合递归解决方案 - 请参阅here了解原因,但它归结为您可以多快地减少递归搜索空间。
虽然huge_number
的划分相当快,但绝大多数递归调用都是通过简单地递增n
来完成的。这意味着你将使用 lot 的堆栈空间。
你会更好:
(a)以你的递归解决方案为蓝本的这种野兽的一个例子是:
#include <stdio.h>
long long prime_factor_i (int n, long long huge_number) {
while (n < huge_number) {
if (huge_number % n == 0) {
huge_number /= n;
continue;
}
n++;
}
return huge_number;
}
int main (void) {
int n = 2;
long long huge_number = 60085147514LL;
long long largest_prime = 0;
largest_prime = prime_factor_i (n, huge_number);
printf ("%lld\n", largest_prime);
return 0;
}
从迭代解的输出可以看出,最大因子是10976461
。这意味着递归解决方案中的最后一批递归将需要10个百万堆栈帧的堆栈深度,这不是大多数环境容易应对的。
如果你真的必须使用递归解决方案,你可以通过使用 来检查它的事实来将堆栈空间减少到它的平方根一直到数字,但只有它的平方根。
此外,除了2
之外,每个其他素数都是奇数,因此您只需检查两个加上奇数就可以进一步减半搜索空间。
考虑到这两件事的递归解决方案是:
long long prime_factor_r (int n, long long huge_number) {
// Debug code for level checking.
// static int i = 0;
// printf ("recursion level = %d\n", ++i);
// Only check up to square root.
if (n * n >= huge_number)
return huge_number;
// If it's a factor, reduce the number and try again.
if (huge_number % n == 0)
return prime_factor_r (n, huge_number / n);
// Select next "candidate" prime to check against, 2 -> 3,
// 2n+1 -> 2n+3 for all n >= 1.
if (n == 2)
return prime_factor_r (3, huge_number);
return prime_factor_r (n + 2, huge_number);
}
你可以看到我也删除了(在我看来很尴尬)的构造:
if something then
return something
else
return something else
我更喜欢来自以下的不那么大量缩进的代码:
if something then
return something
return something else
但这只是个人偏好。在任何情况下,这会使您的递归级别降至1662(取消注释调试代码以验证)而不是一千万,这是一个相当大的减少但仍然不完美。在我的环境中运行良好。
答案 3 :(得分:0)
崩溃原因是堆栈溢出。我为你的程序添加一个计数器并执行它(在ubuntu 10.04 gcc 4.4.3上)计数器在核心转储之前停在“218287”。更好的解决方案是使用循环而不是递归。