我的Java Sieve代码很慢,不能按预期的时间复杂度进行扩展

我的Java Sieve代码很慢,不能按预期的时间复杂度进行扩展,java,multithreading,time-complexity,sieve-of-eratosthenes,sieve,Java,Multithreading,Time Complexity,Sieve Of Eratosthenes,Sieve,我已经用Java编写了下面的“分段筛”程序。它需要对一系列数字进行筛选,使用“筛选素数”(primes arraylist变量)划掉组合数,然后返回尚未划掉的素数。代码如下: public ArrayList<Integer> sieveWorker(int start, int last, ArrayList<Integer> primes) { System.out.println("Thread started for range: " + start +

我已经用Java编写了下面的“分段筛”程序。它需要对一系列数字进行筛选,使用“筛选素数”(primes 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;
}
public ArrayList-sievewrker(int-start、int-last、ArrayList-primes){
System.out.println(“范围为“+start+”-“+last”的线程已启动);
ArrayList nonPrimes=新的ArrayList();
ArrayList素数=新的ArrayList();
ArrayList编号=新的ArrayList();
//要筛选的数字

对于(int i=start;i而言,罪魁祸首是
数字。removeAll(nonPrimes)
调用
数字中每个数字的调用(其中有O(n)个)搜索所有
非primes
(其中有O个(n个log last))以检查成员身份(并且
非primes
也未排序).n是编号的长度,
n=last-start

因此,不是对每个非素数进行O(1)标记,而是对每个非素数进行O(n log last)实际删除。因此,上述O(n^2)操作总体上是这样的

克服这一问题的一种方法是使用简单数组,并标记非素数。删除会破坏直接地址功能。如果使用它,操作必须在线,接近O(1)每个数字的操作。这可以通过使非素数成为一个排序列表来实现,然后以线性方式从数字中删除它们。这两项任务都可以用数组来完成。

解释 必须查找元素。这基本上是包含和包含在
ArrayList上的
速度很慢,
O(n)

它从左到右迭代整个列表并删除匹配的元素。它对
非primes
集合中的每个元素都执行此操作。因此,仅对于
removeAll
部分,您将获得
O(n*|非primes)
的复杂性


解决方案

有一个简单的修复,交换你的数据结构。如<代码> HASSET < /C> >为<代码> O(1)< /C> >包含查询。因为你只需要<代码>添加< /代码>和<代码> ReaveWOR/<代码> >代码<数字>代码>,请考虑使用<代码> HasStuts<代码>,这两个代码都在<代码> O(1)(AMMORIZE)中运行。

仅代码更改:

Set<Integer> numbers = new HashSet<>();
Set number=new HashSet();
另一种可能是进行一些算法更改。通过在收集元素时标记元素,最终可以避免
移除所有
。优点是可以使用数组。最大的优点是避免了装箱的
Integer
类,直接在基本体
int
上运行,这些基本体是fa不要占用太多空间。请查看@Will\u Ness的答案以了解此方法的详细信息



您的<代码> PrimeCopys
变量在您的方法中从未被使用。请考虑删除它。

这实际上是用于代码审查的东西。但是对于初学者来说,停止重新计算头一次执行代码> int=头=头/<代码>,在每次使用“代码>头*<代码> >时使用同样的代码。<代码>头* 2 < /代码>同样如此。ght希望在这里使用流,这样您将受益于并行处理。使用数组而不是列表可能会加快速度。这不适用于CodeReview,因为正如OP(关于复杂性)所述,此代码未按预期工作。是的,用于实际测量经验增长顺序!!
Set<Integer> numbers = new HashSet<>();