【发布时间】:2015-09-04 04:44:07
【问题描述】:
我想找出 100 亿以下的所有素数。这是 int 可以容纳的 5 倍(这是数组的限制,无论类型如何)。尝试一次分配超过 12 亿个会导致堆空间不足错误。我尝试使用 List 而不是布尔数组,但 arrayLists 的 set element 方法只能索引到 int。让我烦恼的是,很快进入筛子的元素少于整数个没有被划掉。一种应该有效的方法是创建一个由 10 个数组组成的分区并将它们粉碎在一起......但这会很丑陋。如果您对解决此问题的优雅方法有任何建议,请告诉我。 (除了使用 Python 哈哈)。我已经有一个 n^2/2 蛮力实现,但这需要很长时间才能运行,所以我真的想尽可能快地解决这个问题。我的高达 12 亿的 Sieve 实现如下:
public class SieveEratosthenes {
private boolean[] nums;
public static void main(String[] args) {
int n = 1000000;
SieveEratosthenes s = new SieveEratosthenes(n);
for(int i=0;i<s.nums.length;i++){
if(s.nums[i]){
System.out.println(i);
}
}
}
public SieveEratosthenes(int max){
sieve(max);
}
private boolean[] sieve(int max){
nums = new boolean[max+1];
initFlags();
for(int i=2;i*i<max;i++){
for(int j=i*i;j<=max;j+=i){//cross off non-primes
nums[j]=false;
}
}
return nums;
}
private void initFlags(){
if(nums != null&&nums.length>1){
nums[0]=false;
nums[1]=false;
nums[2]=true;
}
for(int i=3;i<nums.length;i++){
nums[i]=true;
}
}
public List<Long> sieveToList(){
List<Long> sieveList = new ArrayList();
for(int i=0;i<nums.length;i++){
if(nums[i]){
sieveList.add((long)i);
}
}
return sieveList;
}
【问题讨论】:
-
使用Java的
BigInteger类,痛苦会少很多! -
您只能在 HashSet
中放入素数。这样可以节省大量内存。 -
@Am_I_Helpful 提问者没有使用
ints 作为素数列表的元素,而是使用boolean[],其中第 n 个元素描述了 n。问题是数组索引是int值,因此只能描述直到MAX_INT的数字的素数。除非存在由BigInteger值索引的列表结构,否则在此实现中使用BigInteger不能替换int。 -
@Alden - 这就是我的建议,删除数组练习,带上一个列表或其他东西,然后实现相同的程序。那会少很多痛苦。我建议他改变实施方式!
-
stackoverflow.com/questions/8804435/… 可能是
OpenBitSet(参见answer)。另请注意,您可以利用 2^n 永远不是素数的事实