【问题标题】:How to generate huge amount of prime numbers in java?如何在java中生成大量素数?
【发布时间】:2017-02-01 00:31:15
【问题描述】:

为了解决一个问题,我必须生成一个从 1 到 3000000 的素数列表,所以我尝试了几种方法来做到这一点,不幸的是都失败了......

第一次尝试:因为所有大于 2 的素数都是奇数,所以我首先生成一个以 3 开头的奇数列表,称为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);
    }


  }
}

【问题讨论】:

  • " 好吧,我猜 3000000 确实是一个很大的数字,呵呵" 不是。 Eratosthenes 的筛子应该可以轻松处理这个问题。
  • 哦!我知道。这就是我在第二次和第三次尝试时使用的方式,但它仍然内存不足。您能否在第二次和第三次尝试中查看我的代码并告诉我出了什么问题?拜托!
  • int j = i * i => int j = 2 * i,首先。
  • primeGenerator 方法不会耗尽内存,前提是它可以分配isPrime 数组:此后不再分配内存。

标签: java algorithm list primes


【解决方案1】:

修复了埃拉托色尼筛法的实现(您的第三次尝试)。我相信它应该可以满足您的需求。

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);
    }
}

【讨论】:

  • 如果内存有问题,也可以考虑使用BitSet
  • 嗯……不知道……还是越来越慢,那我得强行退出IDE了。
【解决方案2】:

另一种方法是从一个由 2 和 3 组成的素数列表开始。有一个方法isPrime(int) 通过将候选数除以该列表中的每个素数来确定一个数字是否为素数。定义另一个方法findNextPrime()isPrime() 可以根据需要调用该方法来扩展列表。与维护所有奇数和合数的列表相比,这种方法的开销要低得多。

【讨论】:

    【解决方案3】:

    在您的情况下,内存不是问题。大小为n = 3000000 的数组可以在函数的堆栈框架内定义。实际上,大小为 10^8 的数组可以在函数内部安全地定义。如果您需要更多,请将其定义为全局变量(实例变量)。来到您的代码中,您的第三个代码中有一个IndexOutOfBoundsException。您只需要检查直到sqrt(n) 的数字因子。因素成对存在一个因素&lt;=sqrt(n) 和其他&gt;=sqrt(n)。因此,您可以优化 Eratosthenes 算法的筛分。这是一个指向one wonderful tutorial 的链接,了解筛子的各种优化。

    【讨论】:

    • 如果您在 sieve 实现中包含一些解决问题的代码或提供您建议的改进算法的简短示例,这将对您的回答有所帮助。
    【解决方案4】:

    这可以在几毫秒内生成高达Integer.MAX_VALUE 的素数。它也不像埃拉托色尼筛法那样占用大量内存。

    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);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-02-09
      • 2014-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多