判断一个数是否是质数
最暴力的解法
- 利用质数的性质:设i为质数,则i只能被 1 和 i整除。
- 因此对于i,我们可以令 2..i-1 依次除以i,如果均不能被整除,则说明是质数。
- 代码如下
private static boolean isPrime1(int nr) {
for (int i = 2; i < nr; i++) {
if (nr % i == 0) return false;
}
return true;
}
稍微暴力的方法
- 同样利用其性质,但我们可以注意到,当 x > i / 2 时,则 x 肯定不能被 i 整除。
- 对于i,我们可以令 2..x 依次除以i,其中x为sqrt(i)
- 代码如下
private static boolean isPrime2(int nr) {
for (int i = 2; i*i <= nr; i++) {
if (nr % i == 0) return false;
}
return true;
}
效率更高的算法
- 提供一个数组
nums = {2, 3, 4, 5,... 17}
- 我们知道 nums[0] 为质数,将nums中所有能被nums[0]整除的数移除,此时数组为
nus = {2, 3, 5, 7, 9, 11, 13, 15, 17}
- 接着将所有能被 3 整除的数移除。此时为
nums = {2, 3, 5, 7, 11, 13, 17}
- 接下来的数是 5,因为 5*5 > 17,所以移除过程结束。此时的nums值为输入nums中的所有素数。
- 上面的步骤之所以正确是因为:合数必定可以由质数相乘得到,则对任意质数i,如果其不能被sqrt(i)前的所有质数整除,则其必定为质数(小于 sqrt(i) 的合数必定可以被小于 sqrt(i) 的质数合成)。
- 代码如下
private static void primeList(List<Integer> nums) {
for (int i = 0; i < nums.size(); i++) {
if (nums.get(i)*nums.get(i) <= nums.get(nums.size()-1)) {
for (int j = i+1; j < nums.size(); j++) {
if (nums.get(j) % nums.get(i) == 0) nums.remove(j);
}
} else {
return ;
}
}
}
- 此算法存在的问题也很明显,说它是判断一个数是否是质数获取不太准确,其作用应该是 “打印出小于等于某值的所有质数”
使用素数表
- 上面的算法有一个缺陷,它对输入数组要求较高,要求包含了数组最大值之前的所有素数,且是已排序的。也就是说它不能用来直接判断一个数是否是素数。
- 通常情况下,我们会使用一个素数表。接着用来整除的元素便可以从这个素数表中获取
- 这种算法的局限在于素数表是有限的,对于超出素数表最大值平方的数则需要加上上述方法二的步骤才能判断(尽管这种情况不多)。
- 算法实现同上,只是此时直接从素数表获取素数即可
参考:打印质数的各种算法
完整代码如下:Prime.java