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