簡體   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