【问题标题】:Efficient Prime Number Computing Program Java高效素数计算程序 Java
【发布时间】:2017-11-15 02:49:28
【问题描述】:

所以我试图在 java 中制作一个素数计算器,从 1 到用户给出的范围的上限,并打印出所有的素数。

解决这个问题的一种方法是简单地使用嵌套的 for 循环,并测试范围内的每个数字与小于它的所有数字的可分性。

但是,我认为只测试素数以避免重复因素并加快程序速度会更有效。

例如,如果我们所在的数字是 16,而不是测试它是否可以被 2、3、4、5、...14、15、16 整除,我只能测试出 2、3、5, 7,11,13,一旦找到一个因素就停止。

所以我尝试创建一个数组来存储目前找到的所有素数,并且只使用这些值来测试下一个数字。

这是我的代码,我不知道为什么它不起作用

    Scanner sc = new Scanner (System.in);
    System.out.print ("Enter the upper limit: ");
    int high = sc.nextInt();

    boolean isPrime = true;
    int[] primearray = new int[0];

    for (int num = 1; num <= high; num++)
    {
        for (int x: primearray)
        {
            if (num%x==0)
            {
                isPrime = false;
                break;
            }
        }
        if (isPrime == true) {
            int size = primearray.length;
            primearray = new int[size+1];
            primearray [size] = num;

            System.out.println (num);
        }
    }

【问题讨论】:

    标签: java primes bluej


    【解决方案1】:

    首先,1 不是素数。通过从 1 开始您的外循环,您的素数数组以 1 结束,然后其他所有内容都将测试为非素数。在int num = 2 开始您的外循环。

    其次,当您扩展 primearray 时,您不会复制现有的已知素数。你可以使用

    primearray = Arrays.copyOf(primearray, size+1);
    

    这将创建一个新数组,其中复制了所有旧内容并为另一个值留出空间。

    最后,您可能想查看Sieve of Eratosthenes。该算法的仔细实现将比您当前的算法更有效,每次找到素数时都需要进行昂贵的数组重新分配。您可以使用BitSet 来跟踪筛子需要的标志。

    【讨论】:

      【解决方案2】:

      你的逻辑有问题

      boolean isPrime = true;
      

      这个变量应该在for循环中声明,让我们想象一下,如果你发现4不是素数那么isPrime = false,那么你检查5但是没有任何代码块设置@ 987654326@.

      还有这个块:

      if (isPrime == true) {
          int size = primearray.length;
          primearray = new int[size+1];
          primearray [size] = num;
      
          System.out.println (num);
      }
      

      您创建了新的素数数组,primearray 大小增加了 1,因此primearray 不包含任何旧素数,这在检查素数时会出错。所以你需要将旧的素数复制到新的数组中。

      因为素数以 2 开头,所以你的代码应该是:

      Scanner sc = new Scanner(System.in);
      System.out.print("Enter the upper limit: ");
      int high = sc.nextInt();
      
      int[] primeArray = new int[0];
      for (int num = 2; num <= high; num++)
      {
          boolean isPrime = true;
          for (int x : primeArray)
          {
              if (num % x == 0)
              {
                  isPrime = false;
                  break;
              }
          }
      
          if (isPrime == true)
          {
              primeArray = Arrays.copyOf(primeArray, primeArray.length + 1);
              primeArray[primeArray.length - 1] = num;
              System.out.println(num);
          }
      }
      

      【讨论】:

        【解决方案3】:

        您应该使用埃拉托色尼筛法来寻找素数,而不是测试每个数字的可分性;这种方法比筛分要慢得多。这是从my blog 筛选的实现:

        public static LinkedList sieve(int n)
        {
            BitSet b = new BitSet(n);
            LinkedList ps = new LinkedList();
        
            b.set(0,n);
        
            for (int p=2; p<n; p++)
            {
                if (b.get(p))
                {
                    ps.add(p);
                    for (int i=p+p; i<n; i+=p)
                    {
                        b.clear(i);
                    }
                }
            }
        
            return ps;
        }
        

        【讨论】:

          【解决方案4】:

          正如您所说,关键的简化是仅在找到下一个素数时才测试素数。例如:

          public class PrimeGenerator {
              private long current = 1;
              private final List<Long> primes = new ArrayList<>();
          
              public long next() {
                  do {
                      current++;
                  } while (primes.stream().anyMatch(n -> current % n == 0));
                  primes.add(current);
                  return current;
              }
          
              public LongStream stream() {
                  return LongStream.generate(this::next);
              }
          }
          

          这会在生成每个素数时记录它。

          您可以使用

          生成获取所有素数到某个值
          generator.stream().takeWhile(p -> p < value)...
          

          【讨论】:

            【解决方案5】:

            以前的答案已经解释了您的代码有什么问题。

            我只想分享另一种更有效的方法。示例实现如下。基本上,一旦我们知道 x 是素数,我们也知道 i*x 不是素数。进一步阅读和可视化可用here

            public int countPrimes(int n) {
                        if (n == 0 || n == 1) return 0;
            
                int count = 0;
                boolean[] check = new boolean[n+1];
            
                for (int i = 2; i < n; i++) {
                    if (check[i]) continue;
            
                    for (int j = 1; j <= n / i; j++) {
                        check[j * i] = true;
                    }
            
                    count++;
                }
            
                return count;
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-07-17
              • 2014-04-28
              • 1970-01-01
              • 2019-10-09
              • 2017-03-22
              • 2020-01-29
              • 1970-01-01
              相关资源
              最近更新 更多