Java寻找素数的高效算法

在看Java语言程序设计进阶篇这本书,看一下找素数的算法。

具体要求是给出一个数n,打印出小于等于n的所有素数

第一种方法,代码如下  :

  Scanner input = new Scanner(System.in);
    System.out.print("Find all prime numbers <= n, enter n: ");
    int n = input.nextInt();

    final int NUMBER_PER_LINE = 10; // Display 10 per line
    int count = 0; // Count the number of prime numbers
    int number = 2; // A number to be tested for primeness

    System.out.println("The prime numbers are:");

    // Repeatedly find prime numbers
    while (number <= n) {
      // Assume the number is prime
      boolean isPrime = true; // Is the current number prime?

      // ClosestPair if number is prime
      for (int divisor = 2; divisor <= (int)(Math.sqrt(number)); 
          divisor++) {
        if (number % divisor == 0) { // If true, number is not prime
          isPrime = false; // Set isPrime to false          
          break; // Exit the for loop
        }
      }

      // Print the prime number and increase the count
      if (isPrime) {
        count++; // Increase the count

        if (count % NUMBER_PER_LINE == 0) {
          // Print the number and advance to the new line
          System.out.printf("%7d\n", number);
        }
        else
          System.out.printf("%7d", number);
      }

      // Check if the next number is prime
      number++;
    }
    
    System.out.println("\n" + count + 
      " prime(s) less than or equal to " + n);

这是最简单也是我一直用的方法,大一刚学C语言书上差不多的示例代码就是这个了。。。

通过对   2 ~ (int)sqrt(number) 进行遍历,来判断number%k==0,如果可以整除,代表不是素数。但是这样做有一个问题,每一次for循环都需要计算Math.sqrt(number),效率不太高。

所以可以把平方根的计算放到循环外面,用一个变量squareRoot来保存每次的值,就省去了循环内部的计算。

第2种方法:

然而第一种方法还是图样图森破。

仔细考虑一下,可以发现,对于2个完全平方数之间的数,比如36到48之间的数,它们的平方根通过int转换之后的值都是6,所以对上述代码,可以进行小的修改

  Scanner input = new Scanner(System.in);
        System.out.print("Find all prime numbers <= n, enter n: ");
        int n = input.nextInt();

        // A list to hold prime numbers
        java.util.List list =
                new java.util.ArrayList<>();

        final int NUMBER_PER_LINE = 10; // Display 10 per line
        int count = 0; // Count the number of prime numbers
        int number = 2; // A number to be tested for primeness
        int squareRoot = 1; // Check whether number <= squareRoot

        System.out.println("The prime numbers are \n");

        // Repeatedly find prime numbers
        while (number <= n) {
            // Assume the number is prime
            boolean isPrime = true; // Is the current number prime?

            if (squareRoot * squareRoot < number) squareRoot++;

            // ClosestPair if number is prime
            for (int k = 0; k < list.size()
                    && list.get(k) <= squareRoot; k++) {
                if (number % list.get(k) == 0) { // If true, not prime
                    isPrime = false; // Set isPrime to false
                    break; // Exit the for loop
                }
            }

            // Print the prime number and increase the count
            if (isPrime) {
                count++; // Increase the count
                list.add(number); // Add a new prime to the list
                if (count % NUMBER_PER_LINE == 0) {
                    // Print the number and advance to the new line
                    System.out.println(number);
                }
                else
                    System.out.print(number + " ");
            }

            // Check if the next number is prime
            number++;
        }

        System.out.println("\n" + count +
                " prime(s) less than or equal to " + n);

添加一个变量squareRoot = 1,用来保存平方根,在每一个数进行计算时,计算出平方根

if (squareRoot * squareRoot < number) squareRoot++;

通过一个线性表来保存求出的素数,在求解是否是素数的时候,只需要判断某个数是否能够整除list中比它的平方根小的数即可。

举一个例子,当遍历到11这个数的时候,此时list中保存的素数已经有2,3,5,7四个

遍历到11时,squareRoot = 4 ,11只需要跟list前2个数进行取余运算即可,因为5>4,所以不需要进行遍历,而11%2!=0,11%3!=0,所以可以判断11为素数,加入list

方法3:

 Scanner input = new Scanner(System.in);
    System.out.print("Find all prime numbers <= n, enter n: ");
    int n = input.nextInt();
    
    boolean[] primes = new boolean[n + 1]; // Prime number sieve
    
    // Initialize primes[i] to true
    for (int i = 0; i < primes.length; i++) {
      primes[i] = true; 
    }
    
    for (int k = 2; k <= n / k; k++) {
      if (primes[k]) {
        for (int i = k; i <= n / k; i++) {
          primes[k * i] = false; // k * i is not prime
        }
      }
    }
    
    final int NUMBER_PER_LINE = 10; // Display 10 per line
    int count = 0; // Count the number of prime numbers found so far
    // Print prime numbers
    for (int i = 2; i < primes.length; i++) {
      if (primes[i]) {
        count++;
        if (count % 10 == 0) 
          System.out.printf("%7d\n", i);
        else
          System.out.printf("%7d", i);          
      }
    }
    
    System.out.println("\n" + count + 
      " prime(s) less than or equal to " + n);

方法3是埃拉托色尼的素数筛法,要求小于等于n的所有数,先创建一个长度为N+1的布尔型数组(包括0)来保存每一个数是否为素数。

数组长度为n+1,其实真的有用的索引是2~n,前面的0和1在素数计算中并没有意义。

筛法主要的思路是,对于这么多数,如果一个数是素数的倍数,那么那个数肯定不是素数。所以从k=2开始,将数组中2的倍数(不包括2)的布尔值改为false,代表它们不是素数,然后k=3,进行一次筛选,k=5,进行一次筛选。。。。一直遍历到k的平方根为止,剩下的留在数组中的数就是素数

算法就完成了





你可能感兴趣的:(JAVA)