在看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的平方根为止,剩下的留在数组中的数就是素数
算法就完成了