在c中使用递归找到最大素数因子

时间:2012-01-30 02:20:44

标签: c recursion prime-factoring

编写了我认为是一个很好的算法的代码,用于使用递归查找大数的最大素因子。我的程序崩溃时,任何大于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);
}

任何关于它为什么会崩溃以及如何改进它的信息将非常感激。

4 个答案:

答案 0 :(得分:1)

您的意思是n+1而不是n++。 使用后n++递增n ,因此递归调用获得原始值n

答案 1 :(得分:1)

你正在溢出堆栈,因为n ++后递增值,使用与当前调用相同的值进行递归调用。

答案 2 :(得分:0)

即使解决使用后递增的问题以使递归永远持续,这也不适合递归解决方案 - 请参阅here了解原因,但它归结为您可以多快地减少递归搜索空间。

虽然huge_number的划分相当快,但绝大多数递归调用都是通过简单地递增n来完成的。这意味着你将使用 lot 的堆栈空间。

你会更好:

  • 使用迭代解决方案,你不会烧掉堆栈(如果你只想解决问题)(a);或
  • 如果你只是想学习递归,
  • 找到一个更合适的递归问题。

(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”。更好的解决方案是使用循环而不是递归。