[英]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.