簡體   English   中英

如何在Java中生成大量素數?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM