[英]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
也未排序)。 n是numbers
的长度, 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
结构包含查询。 因为你只需要add
和removeAll
上numbers
,可以考虑使用HashSet
相反,它运行在两个O(1)
(ammortized)。
仅更改代码:
Set<Integer> numbers = new HashSet<>();
另一种可能性是进行一些算法更改。 您可以通过在收集元素时标记元素来最终避免removeAll
。 好处是您可以使用数组。 这样做的最大好处是,您可以避免使用盒装的Integer
类,而直接在原语int
上运行,而原语int
更快,并且不会占用太多空间。 有关此方法的详细信息,请检查@Will_Ness的答案。
您的primeNumbers
变量从未在您的方法中使用。 考虑删除它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.