簡體   English   中英

我的Java Sieve代碼很慢,無法按預期的時間復雜度進行擴展

[英]My Java Sieve code is slow and not scaling at the expected time complexity

我用Java編寫了以下“分段篩”程序。 篩選需要一定范圍的數字,使用“篩除質數”(質數arraylist變量)將合成數相除,然后返回尚未被相除的質數。 這是代碼:

public ArrayList<Integer> sieveWorker(int start, int last, ArrayList<Integer> primes) {

    System.out.println("Thread started for range: " + start + "-" + last);
    ArrayList<Integer> nonPrimes = new ArrayList<Integer>();
    ArrayList<Integer> primeNumbers = new ArrayList<Integer>();
    ArrayList<Integer> numbers = new ArrayList<Integer>();

    //numbers to be sieved
    for (int i = start; i <= last; i += 2) {
        numbers.add(i);
    }

    //identifies composites of the sieving primes, then stores them in an arraylist
    for (int i = 0; i < primes.size(); i++) {

        int head = primes.get(i);

        if ((head * head) <= last) {
            if ((head * head) >= start) {
                for (int j = head * head; j <= last; j += head * 2) {
                    nonPrimes.add(j);
                }
            } else {
                int k = Math.round((start - head * head) / (2 * head));
                for (int j = (head * head) + (2 * k * head); j <= last; j += head * 2) {
                    nonPrimes.add(j);
                }
            }
        }

    }

    numbers.removeAll(nonPrimes);
    System.out.println("Primes: " + numbers);
    return numbers;
}

我的問題是它非常慢,並且執行時的復雜度為o(n ^ 3),而不是預期的復雜度為o(n log log n)。 我需要有關優化和糾正其時間復雜度的建議。

罪魁禍首是numbers.removeAll(nonPrimes)調用,它針對數字中的每個numbers (並且有O(n)個)潛在地搜索所有非nonPrimes (並且它們中有O(n個log log個) )以進行檢查成員資格( nonPrimes也未排序)。 nnumbers的長度, n = last - start

因此,代替每個非質數的O(1) 標記 ,您可以對它們中的每個O(n)進行O(n log log last)實際刪除。 因此,上述O(n ^ 2)操作總體而言。

解決此問題的一種方法是使用簡單的數組,並標記非素數。 刪除會破壞直接地址功能。 如果完全使用它,則操作必須在線 ,每個數字接近O(1)個操作。 這可以通過使非素數成為有序列表,然后將其從線性迭代的數字中刪除來實現。 同樣,這兩個任務最容易用數組完成。

說明

numbers.removeAll(nonPrimes);

必須找到元素。 基本上, 包含包含ArrayList上的速度很慢, O(n)

它從左到右迭代整個列表,並刪除匹配的元素。 它會對nonPrimes集合中的每個元素執行此操作。 因此,僅對於removeAll部分,您將獲得O(n * |nonPrimes|)的復雜度。


有一個簡單的解決方法,可以交換您的數據結構。 O(1)構造的HashSet結構包含查詢。 因為你只需要addremoveAllnumbers ,可以考慮使用HashSet相反,它運行在兩個O(1) (ammortized)。

僅更改代碼:

Set<Integer> numbers = new HashSet<>();

另一種可能性是進行一些算法更改。 您可以通過在收集元素時標記元素來最終避免removeAll 好處是您可以使用數組。 這樣做的最大好處是,您可以避免使用盒裝的Integer類,而直接在原語int上運行,而原語int更快,並且不會占用太多空間。 有關此方法的詳細信息,請檢查@Will_Ness的答案。


注意

您的primeNumbers變量從未在您的方法中使用。 考慮刪除它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM