在Java中实现素数(质数)的判断与查找是编程学习中的经典问题,素数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数,掌握素数的算法不仅有助于理解基础编程逻辑,还能为后续更复杂的数学计算打下基础,本文将详细介绍几种在Java中判断和查找素数的方法,并分析其优缺点及适用场景。

素数的基本判断方法
最直观的素数判断方法是试除法,其核心思想是:对于一个整数n,检查从2到n-1的所有整数是否能整除n,如果都不能整除,则n是素数,但实际上,只需检查到√n即可,因为如果n存在大于√n的因数,那么它必然对应一个小于√n的因数,以下是试除法的Java实现:
public static boolean isPrime(int num) {
if (num <= 1) {
return false;
}
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
优点:实现简单,逻辑清晰,适合小范围数的判断。
缺点:对于大数(如超过10^6),效率较低,因为时间复杂度为O(√n)。
优化后的试除法
在试除法的基础上,可以进一步优化:
- 跳过偶数:除了2,所有偶数都不是素数,因此只需检查奇数。
- 提前处理边界条件:如2和3直接返回true,其他数先判断是否能被2或3整除。
优化后的代码如下:

public static boolean isPrimeOptimized(int num) {
if (num <= 1) return false;
if (num <= 3) return true;
if (num % 2 == 0 || num % 3 == 0) return false;
for (int i = 5; i * i <= num; i += 6) {
if (num % i == 0 || num % (i + 2) == 0) {
return false;
}
}
return true;
}
优化点:减少了循环次数,时间复杂度仍为O(√n),但常数因子更小,效率更高。
埃拉托斯特尼筛法(筛法)
如果需要查找一定范围内的所有素数(如1到n),筛法是更高效的选择,其原理是:
- 初始化一个长度为n+1的布尔数组,标记所有数为素数(true)。
- 从2开始,将2的倍数标记为非素数(false)。
- 继续处理下一个未被标记的数,重复步骤2,直到√n。
- 最终数组中仍为true的数即为素数。
以下是筛法的Java实现:
public static List<Integer> sieveOfEratosthenes(int n) {
boolean[] isPrime = new boolean[n + 1];
Arrays.fill(isPrime, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i * i <= n; i++) {
if (isPrime[i]) {
for (int j = i * i; j <= n; j += i) {
isPrime[j] = false;
}
}
}
List<Integer> primes = new ArrayList<>();
for (int i = 2; i <= n; i++) {
if (isPrime[i]) {
primes.add(i);
}
}
return primes;
}
优点:时间复杂度为O(n log log n),适合批量生成素数。
缺点:空间复杂度为O(n),需要额外存储数组。

概率性素数测试(Miller-Rabin测试)
对于极大数(如超过10^18),确定性算法效率低下,此时可采用概率性测试,Miller-Rabin测试是一种常用的素性概率测试方法,通过多次随机测试降低误判率,以下是简化实现:
public static boolean millerRabinTest(int num, int iterations) {
if (num <= 1) return false;
if (num <= 3) return true;
if (num % 2 == 0) return false;
int d = num - 1;
while (d % 2 == 0) {
d /= 2;
}
Random random = new Random();
for (int i = 0; i < iterations; i++) {
int a = 2 + random.nextInt(num - 3);
int x = (int) Math.pow(a, d) % num;
if (x == 1 || x == num - 1) continue;
while (d != num - 1) {
x = (x * x) % num;
d *= 2;
if (x == 1) return false;
if (x == num - 1) break;
}
if (x != num - 1) return false;
}
return true;
}
优点:时间复杂度为O(k log³n),k为测试次数,适合大数。
缺点:结果是概率性的,需合理设置测试次数以平衡准确性和效率。
实际应用中的选择
- 小范围判断(如n < 10^6):优先使用优化后的试除法,简单高效。
- 批量生成素数(如1到n):选择筛法,性能最佳。
- 极大数判断(如密码学应用):采用Miller-Rabin等概率性测试。
注意事项
- 边界条件:始终注意处理n ≤ 1的情况,避免逻辑错误。
- 数据类型:大数计算时使用
long或BigInteger防止溢出。 - 性能优化:对于高频调用,可预先计算并缓存素数表。
通过以上方法,可以灵活应对Java中不同场景的素数需求,理解算法原理并选择合适的方法,是提升编程能力的关键一步。


















