【问题标题】:How to correct my prime factorization program?如何纠正我的素数分解程序?
【发布时间】:2015-03-30 18:21:02
【问题描述】:

这是我输出给定数的素数分解的程序。我仍然只是 java 的初学者,所以我知道它不是最有效的代码。当我输入相对较大的数字时,就会出现问题。

输入:11 输出:11

输入:40 输出:2 2 2 5

输入:5427 输出:3 3 3 3 67

输入:435843 输出:3 3 79 613

输入:23456789 输出:无(似乎存在无限循环,代码应返回 23456789,因为它本身就是一个素数)

什么可能导致这个问题?

import java.util.Scanner;

public class PrimeFactorization {
    public static boolean isPrime(long n) {
        boolean boo = false;
        long counter = 0;
        if (n == 1) {
            boo = false;
        } else if (n == 2) {
            boo = true;
        } else {
            for (long i = 2; i < n; i++) {
                if (n % i == 0) {
                    counter++;
                }
            }
            if (counter == 0) {
                boo = true;
            }
        }
        return boo;
    }

    public static void primeFactorization(long num) {
        for (long j = 1; j <= num; j++) {
            if (isPrime(j)) {
                if (num % j == 0) {
                    while (num % j == 0) {
                        System.out.printf(j + " ");
                        num = num / j;
                    }
                }
            }
            if (num == 1) {
                break;
            }
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("Enter any number:");
        long num = scanner.nextLong();
        System.out.print("Prime factorization of your number is: ");
        primeFactorization(num);
        scanner.close();
    }
}

【问题讨论】:

  • 请包含primeFactorization 方法的其余部分;看起来你只复制了最后一部分。

标签: java primes


【解决方案1】:

没有实际的错误——你只是在以一种非常低效的方式做事。基本上,在除法之前,您要检查 1 到 23456789 之间的每个数字的素数。

做这个检查绝对没有意义。当你从 1 到 23456789 时,每次你发现一个因子,你就知道它一定是素数,因为你已经把所有较小的因子分开了。因此,如果您执行以下所有操作,它仍然可以正常工作,而且速度更快。

  • 完全删除isPrime 方法。
  • 删除行if (isPrime(j)) {,以及匹配的}
  • 更改循环,使 j 从 2 开始,如 for(long j = 2 ; j &lt;= num ; j++) {
  • 从循环末尾删除if (num == 1) { break; }。它根本没有任何用处。

【讨论】:

  • 您的解决方案似乎不起作用,现在我的代码不会为任何给定的数字输出任何数字,无论大小。
  • 哦,你需要从 2 而不是 1 开始 j,否则你只是一遍又一遍地除以 1。我将编辑解决方案。
【解决方案2】:

无论代码的效率如何,分解大数都需要一段时间 - 时间长到让人感觉计算机挂了。鉴于您的代码,即使是非常大的数字也需要很长时间。

您可以做的主要事情是提高代码的效率,注意对于数字的任何一对因数,其中一个不会超过该数的平方根。您可以使用这个事实来限制循环,以将 O(n) 的算法顺序减少到 O(log n)。

long sqrt = Math.sqrt(number);

for (long i = 2; i < sqrt; i++) {
    ...

你可以做很多其他的事情,但这种改变会产生最大的影响。

如果number 在循环期间更改值(例如在第二个因式分解循环中),您当然需要重新计算最终值:

for (...)
    // if number changes
    sqrt = Math.sqrt(number);

【讨论】:

  • number 是素数或只有两个因子时,这会更快。当number 有很多因素时,它会变慢。在原始算法中,num 每找到一个因数就递减,每次找到一个因数,剩下的数就少了。您的方法没有考虑到这一点。现在,随着原始数字的值越来越高,这些值中越来越大的比例具有多个因子,而越来越小的比例是素数。这意味着在一般情况下,这种变化实际上会使性能...
  • ...恶化,而不是改善它。当然,在原始数字为 23456789 的特定情况下,这是一种改进,只是因为该数字恰好是素数。
  • @david 我不确定您要表达什么观点。从 2 到 sqrt(num) 的迭代比从 2 到 num 的迭代需要更少的迭代 - 只是没有解决这个问题。它必须更快。至于 second 循环,寻找因素,我并不是建议改变循环的内容,只是将外部循环限制为 sqrt(num)。同样,这 必须 比在 num 处设置上限更快。正如我所说,还有更多的事情可以做,但是通过如此简单的更改从 O(n) 到 O(log n) 肯定是物有所值。
  • 在这里,更详细地说,您的答案有什么问题。真的达不到您通常的标准,我仍在努力理解为什么我还没有投反对票。 (1) 我认为您误解了 OP 的原始代码。在一般情况下,它不会从 1 一直迭代到 n。它从 1 迭代到 n 的最大素因子。因此,例如,如果 n 为 60(即 2 x 2 x 3 x 5),那么它会从 1 迭代到 5。您的版本是否是改进取决于哪个更大 - sqrt(n) 或n的最大素数。现在对于大多数小 n,以及所有...
  • ... prime n, sqrt(n) 会更小,因此您的代码将比 OP 更快。但是如果 n 有很多因素,您的代码将比 OP 慢。现在,随着我们进入更大的数字,质数变得越来越稀疏,因子很少的值也是如此。因此,随着 n 变得越来越大,您的代码越来越有可能比 OP 更差,而不是更好。您声称它必须更快是不真实的——一旦 n 变得足够大,它更有可能变慢。 (2) 您声称您的算法是O(log(n)) - 不正确。至少是O(sqrt(n)), ...
猜你喜欢
  • 2014-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-25
相关资源
最近更新 更多