[英]How to generate huge amount of prime numbers in java?
为了解决一个问题,我必须生成一个从1到3000000的质数列表,所以我尝试了几种方法来完成此操作,但不幸的是所有方法都失败了...
首先尝试:因为所有大于2的质数都是奇数,所以我首先生成一个以3 allOddNums
的奇数列表,称为allOddNums
。 然后生成一个名为allComposite
的所有复合数字的列表。 然后,我从allOddNums
删除allComposite
中的所有数字,以获得质数。 这是我的代码:
/** Prime Numbers Generation
* Tony
*/
import java.util.*;
public class PrimeNumG {
public static void main(String[] args) {
List <Long> allOddNums = new ArrayList<Long>();
for (long i = 3; i < 200; i += 2) {
allOddNums.add(i);
}
// composite number generator:
List <Long> allComposite = new ArrayList<Long>();
for (long a = 2; a < Math.round(Math.sqrt(3000000)); a += 2) {
for (long b = 2; b < Math.round(Math.sqrt(3000000)); b += 2) {
allComposite.add(a*b);
}
}
// remove duplicated:
Set <Long> hs = new HashSet<Long>();
hs.addAll(allComposite);
allComposite.clear();
allComposite.addAll(hs);
// remove all composite from allRealNums = allPrime
allOddNums.removeAll(allComposite);
allOddNums.add(0, (long)2);
System.out.printf("%s ", allOddNums);
Scanner sc = new Scanner(System.in);
int times = sc.nextInt();
for (int i = 0; i < times; i++) {
int index = sc.nextInt();
System.out.print(allOddNums.get(index) + " ");
}
}
}
在这种情况下,当我需要生成一些质数时,它可以正常工作。 但是,如果我要生成直到3000000,它会使我失败(用完内存)。
第二次尝试:我在网上搜索,找到了一种名为sieve of Eratosthenes
的算法。 然后我首先生成2、3、5、7、9 ...(所有奇数+ 2),然后我删除3之后的每个第3个数字和5之后的每个第5个数字。代码如下:
/** Prime Number Generator
* Tony
*/
import java.util.*;
public class Solution61 {
public static void main(String[] args) {
List<Long> l1 = new ArrayList<Long> ();
// l1 generator: 3 5 7 9 11 ...
for (long d = 3; d < 100; d += 2) {
l1.add(d);
}
l1.add(1, (long)2); // 2 3 5 ...
removeThird(l1); // rm 3rd after 3
removeFifth(l1); // rm 5th after 5, now the l1 will be prime number
Scanner sc = new Scanner(System.in);
int times = sc.nextInt();
for (int i = 0; i < times; i++) {
int index = sc.nextInt();
System.out.print(l1.get(index) + " ");
}
}
/** removeThird : remove every 3rd number after 3
* param List | return void
*/
private static void removeThird(List<Long> l) {
int i = 1;
int count = 0;
while (true) {
if (count == 3) {
l.remove(i);
count = 1;
}
i ++;
count ++;
if (i > l.size()) {
break;
}
}
}
/** removeThird : remove every 5th number after 5
* param List | return void
*/
private static void removeFifth(List<Long> l) {
int i = 2;
int count = 0;
while (true) {
if (count == 5) {
l.remove(i);
count = 1;
}
i ++;
count ++;
if (i > l.size()) {
break;
}
}
}
}
这仍然不能完成任务,因为它还会耗尽内存。
第三次尝试:我尝试生成1到3000000,然后删除每个数字都是质数和另一个数的乘积。 代码如下:
/** print all the prime numbers less than N
* Tony
*/
public class primeGenerator {
public static void main(String[] args) {
int n = 3000000;
boolean[] isPrime = new boolean[n];
isPrime[0] = false; // because 1 is not a prime number
for (int i = 1; i < n; i++) {
isPrime[i] = true;
} // we set 2,3,4,5,6...to true
// the real number is always (the index of boolean + 1)
for (int i = 2; i <= n; i++) {
if (isPrime[i-1]) {
System.out.println(i);
for (int j = i * i; j < n; j += i /* because j is determined by i, so the third parameter doesn't mater*/) {
isPrime[j-1] = false;
}
}
}
}
}
它仍然让我失望,好吧,猜猜3000000真的是一个很大的数目吧? 是否有任何简单而出色的新秀友好方式生成低于3000000的素数? 谢谢!
第四次尝试:@jsheeran这段代码是否在您的答案下面? 当我达到1093时,它变得越来越慢,并且IDE仍然崩溃。 请告诉我我是否误解了您的方法,谢谢!
/** new approach to find prime numbers
* Tony
*/
import java.util.*;
public class PrimeG {
/** isPrime
* To determine whether a number is prime by dividing the candidate number by each prime in that list
*/
static List<Long> primes = new ArrayList<Long> ();
private static void isPrime(long n) {
boolean condition = true;
for (int i = 0; i < primes.size(); i++) {
if (n % primes.get(i) == 0) {
condition = condition && false;
}
}
if (condition) {
findNextPrime(n);
}
}
/** findNextPrime
* expand the list of prime numbers
*/
private static void findNextPrime(long n) {
primes.add(n);
}
public static void main(String[] args) {
primes.add((long)2);
primes.add((long)3);
primes.add((long)5);
primes.add((long)7);
for (int i = 8; i < 3000000; i++) {
isPrime(i);
System.out.printf("%s", primes);
}
}
}
修复了Eratosthenes筛网的实现(您的第三次尝试)。 我相信它应该可以满足您的需求。
public static void main (String[] args) throws java.lang.Exception {
int n = 3000000;
boolean[] isPrime = new boolean[n+1];
for (int i = 2; i <= n; i++) {
isPrime[i] = true;
}
for (int factor = 2; factor*factor <= n; factor++) {
if (isPrime[factor]) {
for (int j = factor; factor*j <= n; j++) {
isPrime[factor*j] = false;
}
}
}
for (int i = 2; i <= n; i++) {
if (isPrime[i]) System.out.println(i);
}
}
一种替代方法是从由2和3组成的素数列表开始。使用isPrime(int)
方法通过将候选数除以该列表中的每个素数来确定数字是否为素数。 定义另一个方法findNextPrime()
, isPrime()
可以调用该方法以根据需要扩展列表。 与维护所有奇数和合成数的列表相比,此方法的开销要低得多。
在您的情况下,内存不是问题。 可以在函数的堆栈框架内定义大小为n = 3000000
数组。 实际上,可以在函数内部安全地定义大小为10 ^ 8的数组。 如果您还需要更多,则将其定义为全球变量(实例变量)。 进入您的代码,您的第三个代码中有一个IndexOutOfBoundsException
。 您只需要检查最多upt sqrt(n)
因子。 因素成对存在,一个因素<=sqrt(n)
,另一个>=sqrt(n)
。 因此,您可以优化Eratosthenes算法的筛选。 这是一个有关各种筛网优化的精彩教程的链接。
这可以在几毫秒内生成最高达Integer.MAX_VALUE
质数。 它也不需要像Eratosthenes的Sieve方法那样占用大量内存。
public class Prime {
public static IntStream generate(int limit) {
return IntStream.range(2, Integer.MAX_VALUE).filter(Prime::isPrime).limit(limit);
}
private static boolean isPrime(int n) {
return IntStream.rangeClosed(2, (int) Math.sqrt(n)).noneMatch(i -> n % i == 0);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.