Java 用Eratosthenes筛寻找素数(最初:有没有更好的方法来准备这个数组?)
注:下面的第2版使用了埃拉托斯坦筛。有几个答案对我最初的问题有所帮助。我选择了Eratosthenes方法的筛子,实现了它,并适当地更改了问题标题和标签。感谢所有帮助过我的人 介绍 我编写了这个奇特的小方法,它生成一个int数组,其中包含小于指定上限的素数。它工作得很好,但我有一个顾虑 方法Java 用Eratosthenes筛寻找素数(最初:有没有更好的方法来准备这个数组?),java,arrays,primes,sieve-of-eratosthenes,Java,Arrays,Primes,Sieve Of Eratosthenes,注:下面的第2版使用了埃拉托斯坦筛。有几个答案对我最初的问题有所帮助。我选择了Eratosthenes方法的筛子,实现了它,并适当地更改了问题标题和标签。感谢所有帮助过我的人 介绍 我编写了这个奇特的小方法,它生成一个int数组,其中包含小于指定上限的素数。它工作得很好,但我有一个顾虑 方法 版本3(由于)使用了: 私有静态int[]生成时间(int max){ 布尔值[]isComposite=新布尔值[max+1]; 对于(int i=2;i*i通过将数组的每个元素与每个可能的因子进行比较
版本3(由于)使用了:
私有静态int[]生成时间(int max){
布尔值[]isComposite=新布尔值[max+1];
对于(int i=2;i*i通过将数组的每个元素与每个可能的因子进行比较来寻找素数的方法效率极低。您可以通过一次对整个数组进行比较来极大地改进它。除了进行更少的比较外,它还使用加法而不是除法。除法要慢得多。最简单的方法是解决方案是返回的某个成员而不是数组。创建一个ArrayList
,然后在最后转换为int[]
有各种各样的第三方IntList
(etc)类,但除非您真的担心装箱几个整数会带来什么影响,否则我不会担心
您可以使用Arrays.copyOf
来创建新的数组。您可能还希望通过每次需要时将大小加倍来调整大小,然后在最后进行修剪。这基本上是模仿ArrayList
的行为。重新构造代码。扔掉临时数组,而是编写只需初始化的函数-测试一个整数。它将相当快,因为您只使用本机类型。然后,例如,您可以循环并构建一个素数整数列表,然后最终将其转换为数组以返回。您使用的是Java 1.5吗?如果需要返回int,为什么不返回list
并使用ArrayList
[]
,您可以在处理结束时将列表转换为int[]
。正如Paul Tomblin指出的,有更好的算法
但是要保持现有的,并且假设每个结果的对象太大:
您只会将其附加到数组中。因此,请使用相对较小的int[]数组。当它完全使用时,将其附加到列表中并创建替换。最后,将其复制到大小正确的数组中
或者,猜测int[]数组的大小。如果它太小,则用比当前数组大小大一小部分的int[]替换。此操作的性能开销将与大小成比例。(这在最近的stackoverflow播客中简要讨论过。)现在您已经有了一个基本的筛子,请注意,内部循环只需要继续到temp[i]*temp[i]>prime
ArrayList
Eratosthenes筛子
Algo使用埃拉托斯坦筛
public static List<Integer> findPrimes(int limit) {
List<Integer> list = new ArrayList<>();
boolean [] isComposite = new boolean [limit + 1]; // limit + 1 because we won't use '0'th index of the array
isComposite[1] = true;
// Mark all composite numbers
for (int i = 2; i <= limit; i++) {
if (!isComposite[i]) {
// 'i' is a prime number
list.add(i);
int multiple = 2;
while (i * multiple <= limit) {
isComposite [i * multiple] = true;
multiple++;
}
}
}
return list;
}
公共静态列表findTime(整数限制){
列表=新的ArrayList();
boolean[]isComposite=new boolean[limit+1];//limit+1,因为我们不使用数组的第0个索引
isComposite[1]=真;
//标记所有复合数字
对于(int i=2;i我有一个非常有效的实现:
我们不保留偶数,因此将内存使用量减半
我们使用位集
,每个数字只需要一位
我们估计区间上素数的上界,因此我们可以适当地为数组设置初始容量
我们不在循环中执行任何类型的除法
代码如下:
public ArrayList<Integer> sieve(int n) {
int upperBound = (int) (1.25506 * n / Math.log(n));
ArrayList<Integer> result = new ArrayList<Integer>(upperBound);
if (n >= 2)
result.add(2);
int size = (n - 1) / 2;
BitSet bs = new BitSet(size);
int i = 0;
while (i < size) {
int p = 3 + 2 * i;
result.add(p);
for (int j = i + p; j < size; j += p)
bs.set(j);
i = bs.nextClearBit(i + 1);
}
return result;
}
公共数组列表筛选(int n){
int上限=(int)(1.25506*n/Math.log(n));
ArrayList结果=新的ArrayList(上限);
如果(n>=2)
结果:增加(2);
整数大小=(n-1)/2;
位集bs=新位集(大小);
int i=0;
而(i
不确定这是否适合您的情况,但您可以看看我的方法。我使用我的方法
公共静态列表筛选(int n){
映射编号=新建LinkedHashMap();
列表素数=新的ArrayList();
//首先生成一个从2到30的整数列表
对于(inti=2;i,我已经使用HashMap并发现它非常简单
import java.util.HashMap;
import java.util.Map;
/*Using Algorithms such as sieve of Eratosthanas */
public class PrimeNumber {
public static void main(String[] args) {
int prime = 15;
HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
hashMap.put(0, 0);
hashMap.put(1, 0);
for (int i = 2; i <= prime; i++) {
hashMap.put(i, 1);// Assuming all numbers are prime
}
printPrimeNumberEratoshanas(hashMap, prime);
}
private static void printPrimeNumberEratoshanas(HashMap<Integer, Integer> hashMap, int prime) {
System.out.println("Printing prime numbers upto" + prime + ".....");
for (Map.Entry<Integer, Integer> entry : hashMap.entrySet()) {
if (entry.getValue().equals(1)) {
System.out.println(entry.getKey());
for (int j = entry.getKey(); j < prime; j++) {
for (int k = j; k * j <= prime; k++) {
hashMap.put(j * k, 0);
}
}
}
}
}
}
import java.util.HashMap;
导入java.util.Map;
/*使用算法,如Eratosthanas的筛选*/
公共类素数{
公共静态void main(字符串[]args){
int素数=15;
HashMap HashMap=新的HashMap();
hashMap.put(0,0);
hashMap.put(1,0);
对于(int i=2;i公共静态空素数(int n){
boolean[]lista=新的boolean[n+1];
对于(int i=2;iwhy你需要一个固定大小的数组?马特·戴维森:我不想返回一个最后有一堆零元素的数组,它感觉太草率了。我要做一个微观优化:将“for”(int j=i;i*j…)替换为“for”(int j=i;j Paul Tomblin:您提供的替换代码遗漏了几个素数。使用位集的效率是大型布尔运算的8倍[]是的,那只是一个占位符,直到我可以在Wikipedia上查找它。Paul Tomblin:我的方法只是返回一个int数组,表示小于指定上限的素数,我认为我不需要筛选任何内容。问题是数组的使用-你不能从Java数组中删除元素,只需0/null即可。Sieve是正交的。但是你要检查数组中的每个值和每个可能的因子。通过做一个筛子,你要检查整个数组中的素数
// Return primes less than limit
static ArrayList<Integer> generatePrimes(int limit) {
final int numPrimes = countPrimesUpperBound(limit);
ArrayList<Integer> primes = new ArrayList<Integer>(numPrimes);
boolean [] isComposite = new boolean [limit]; // all false
final int sqrtLimit = (int)Math.sqrt(limit); // floor
for (int i = 2; i <= sqrtLimit; i++) {
if (!isComposite [i]) {
primes.add(i);
for (int j = i*i; j < limit; j += i) // `j+=i` can overflow
isComposite [j] = true;
}
}
for (int i = sqrtLimit + 1; i < limit; i++)
if (!isComposite [i])
primes.add(i);
return primes;
}
static int countPrimesUpperBound(int max) {
return max > 1 ? (int)(1.25506 * max / Math.log((double)max)) : 0;
}
public static List<Integer> findPrimes(int limit) {
List<Integer> list = new ArrayList<>();
boolean [] isComposite = new boolean [limit + 1]; // limit + 1 because we won't use '0'th index of the array
isComposite[1] = true;
// Mark all composite numbers
for (int i = 2; i <= limit; i++) {
if (!isComposite[i]) {
// 'i' is a prime number
list.add(i);
int multiple = 2;
while (i * multiple <= limit) {
isComposite [i * multiple] = true;
multiple++;
}
}
}
return list;
}
public ArrayList<Integer> sieve(int n) {
int upperBound = (int) (1.25506 * n / Math.log(n));
ArrayList<Integer> result = new ArrayList<Integer>(upperBound);
if (n >= 2)
result.add(2);
int size = (n - 1) / 2;
BitSet bs = new BitSet(size);
int i = 0;
while (i < size) {
int p = 3 + 2 * i;
result.add(p);
for (int j = i + p; j < size; j += p)
bs.set(j);
i = bs.nextClearBit(i + 1);
}
return result;
}
public static List<Integer> sieves(int n) {
Map<Integer,Boolean> numbers = new LinkedHashMap<>();
List<Integer> primes = new ArrayList<>();
//First generate a list of integers from 2 to 30
for(int i=2; i<n;i++){
numbers.put(i,true);
}
for(int i : numbers.keySet()){
/**
* The first number in the list is 2; cross out every 2nd number in the list after 2 by
* counting up from 2 in increments of 2 (these will be all the multiples of 2 in the list):
*
* The next number in the list after 2 is 3; cross out every 3rd number in the list after 3 by
* counting up from 3 in increments of 3 (these will be all the multiples of 3 in the list):
* The next number not yet crossed out in the list after 5 is 7; the next step would be to cross out every
* 7th number in the list after 7, but they are all already crossed out at this point,
* as these numbers (14, 21, 28) are also multiples of smaller primes because 7 × 7 is greater than 30.
* The numbers not crossed out at this point in the list are all the prime numbers below 30:
*/
if(numbers.get(i)){
for(int j = i+i; j<n; j+=i) {
numbers.put(j,false);
}
}
}
for(int i : numbers.keySet()){
for(int j = i+i; j<n && numbers.get(i); j+=i) {
numbers.put(j,false);
}
}
for(int i : numbers.keySet()){
if(numbers.get(i)) {
primes.add(i);
}
}
return primes;
}
import java.util.HashMap;
import java.util.Map;
/*Using Algorithms such as sieve of Eratosthanas */
public class PrimeNumber {
public static void main(String[] args) {
int prime = 15;
HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
hashMap.put(0, 0);
hashMap.put(1, 0);
for (int i = 2; i <= prime; i++) {
hashMap.put(i, 1);// Assuming all numbers are prime
}
printPrimeNumberEratoshanas(hashMap, prime);
}
private static void printPrimeNumberEratoshanas(HashMap<Integer, Integer> hashMap, int prime) {
System.out.println("Printing prime numbers upto" + prime + ".....");
for (Map.Entry<Integer, Integer> entry : hashMap.entrySet()) {
if (entry.getValue().equals(1)) {
System.out.println(entry.getKey());
for (int j = entry.getKey(); j < prime; j++) {
for (int k = j; k * j <= prime; k++) {
hashMap.put(j * k, 0);
}
}
}
}
}
}
public static void primes(int n) {
boolean[] lista = new boolean[n+1];
for (int i=2;i<lista.length;i++) {
if (lista[i]==false) {
System.out.print(i + " ");
}
for (int j=i+i;j<lista.length;j+=i) {
lista[j]=true;
}
}
}