繁体   English   中英

高效素数计算程序Java

[英]Efficient Prime Number Computing Program Java

所以我试图在Java中制作一个质数计算器,该质数从1到用户给定范围的上限,并打印出所有质数。

解决此问题的一种方法是,仅使用嵌套的for循环,并通过小于该范围的所有数字来测试范围内每个数字的可除性。

但是,我认为只测试质数以避免重复的因素并加快程序的效率会更高。

例如,如果我们使用的数字是16,而不是测试是否可以被2,3,4,5,... 14,15,16整除,那么我只能测试2,3,5,7,11 ,13,一旦发现一个因素就停止。

因此,我尝试创建一个数组来存储到目前为止找到的所有素数,并且仅使用这些值来测试下一个数字。

这是我的代码,我不知道为什么它不起作用

    Scanner sc = new Scanner (System.in);
    System.out.print ("Enter the upper limit: ");
    int high = sc.nextInt();

    boolean isPrime = true;
    int[] primearray = new int[0];

    for (int num = 1; num <= high; num++)
    {
        for (int x: primearray)
        {
            if (num%x==0)
            {
                isPrime = false;
                break;
            }
        }
        if (isPrime == true) {
            int size = primearray.length;
            primearray = new int[size+1];
            primearray [size] = num;

            System.out.println (num);
        }
    }

首先,1不是质数。 通过在1处开始外循环,您的质数数组最终以1结束,然后其他所有条件将测试为非质数。 int num = 2开始您的外部循环。

其次,展开primearray时,不会复制现有的已知素数。 您可以使用

primearray = Arrays.copyOf(primearray, size+1);

这将创建一个新的数组,其中复制了所有旧内容,并保留了一个更大的值。

最后,您可能需要查看Eratosthenes筛网 谨慎地实现该算法将比当前算法更有效,因为当前算法每次找到素数都需要进行昂贵的数组重新分配。 您可以使用BitSet来跟踪筛子需要的标志。

你逻辑错了

boolean isPrime = true;

假设应该在for循环中声明此变量,让我们想象一下,如果发现4不是素数,则isPrime = false ,然后检查5但是没有任何代码块设置isPrime = true

和这个块:

if (isPrime == true) {
    int size = primearray.length;
    primearray = new int[size+1];
    primearray [size] = num;

    System.out.println (num);
}

你创造了素数的新阵列, primearray与大小增加1,那么primearray不包含任何旧的素数,同时检查主要是将做出错误的。 因此,您需要将旧质数复制到新数组。

并且由于质数以2开头,因此您的代码应为:

Scanner sc = new Scanner(System.in);
System.out.print("Enter the upper limit: ");
int high = sc.nextInt();

int[] primeArray = new int[0];
for (int num = 2; num <= high; num++)
{
    boolean isPrime = true;
    for (int x : primeArray)
    {
        if (num % x == 0)
        {
            isPrime = false;
            break;
        }
    }

    if (isPrime == true)
    {
        primeArray = Arrays.copyOf(primeArray, primeArray.length + 1);
        primeArray[primeArray.length - 1] = num;
        System.out.println(num);
    }
}

您应该使用Eratosthenes筛子来查找素数,而不是测试每个数的可除性; 该方法比筛分要慢得多。 这是从我的博客中筛选的一种实现:

public static LinkedList sieve(int n)
{
    BitSet b = new BitSet(n);
    LinkedList ps = new LinkedList();

    b.set(0,n);

    for (int p=2; p<n; p++)
    {
        if (b.get(p))
        {
            ps.add(p);
            for (int i=p+p; i<n; i+=p)
            {
                b.clear(i);
            }
        }
    }

    return ps;
}

正如您所说,简化的关键是仅在找到下一个素数时才测试素数。 例如:

public class PrimeGenerator {
    private long current = 1;
    private final List<Long> primes = new ArrayList<>();

    public long next() {
        do {
            current++;
        } while (primes.stream().anyMatch(n -> current % n == 0));
        primes.add(current);
        return current;
    }

    public LongStream stream() {
        return LongStream.generate(this::next);
    }
}

这记录了每个素数的生成。

您可以使用生成所有素数到一定值

generator.stream().takeWhile(p -> p < value)...

先前的答案已经解释了您的代码有什么问题。

我只想分享另一种更有效的方法。 示例实现如下。 基本上,一旦我们知道x是质数,我们也知道i * x不是质数。 在此处进一步阅读和可视化

public int countPrimes(int n) {
            if (n == 0 || n == 1) return 0;

    int count = 0;
    boolean[] check = new boolean[n+1];

    for (int i = 2; i < n; i++) {
        if (check[i]) continue;

        for (int j = 1; j <= n / i; j++) {
            check[j * i] = true;
        }

        count++;
    }

    return count;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM