Java中采用埃拉托斯特尼筛法计算质数

埃拉托斯特尼筛法(Sieve of Eratosthenes)是一种高效求解一定范围内所有质数的经典算法,由古希腊数学家埃拉托斯特尼提出。它的核心思想是:从最小的质数开始,把它的所有倍数全部筛掉,剩下的就是质数。

一、基本概念

  • 质数:也叫素数,是指大于 1 且只能被 1 和自身整除的整数

  • 目标:找出区间 [2,n] 内的所有质数

二、算法思想

  1. 创建一个长度为 n+1 的布尔数组 isPrime

  2. 初始时,假设 2 到 n 全部是质数

  3. 从最小的质数 2 开始:

    • 把 2 的倍数(4, 6, 8, …)全部标记为非质数

  4. 找到下一个仍未被标记的数(如 3):

    • 把 3 的倍数(6, 9, 12, …)全部标记为非质数

  5. 重复以上过程

  6. 最终所有没被标记的数就是质数

三、算法步骤

  1. 创建数组 isPrime[0..n]

  2. isPrime[0]isPrime[1] 设为 false

  3. 其余设为 true

  4. i 从 2 到 √n:

    • isPrime[i] == true

      • ji*in,步长为 i

        • isPrime[j] = false

  5. 遍历数组,输出所有 isPrime[i] == truei


四、代码部分

传统写法:

 1 // 传统写法
 2 public static void calPrimeByNormal(int num){
 3     System.out.println("正在普通法查找 " + num + " 以内的素数...");
 4     int count = 0;
 5     for (int i = 2; i <= num; i++) {
 6         boolean flag = true;
 7         for (int j = 2; j < i; j++) {
 8             if (i % j == 0) {
 9                 flag = false;
10                 break;
11             }
12         }
13         if (flag) {
14             count++;
15         }
16     }
17     System.out.println(num + "以内的素数有" + count + "个");
18 }

 

采用埃拉托斯特尼筛法写法:

 1 // 优化写法 采用埃拉托斯特尼筛法
 2 public static void calPrimeBySieve(int num){
 3     System.out.println("正在以埃拉托斯特尼筛法查找 " + num + " 以内的素数...");
 4     boolean[] isPrime = new boolean[num+1];
 5     Arrays.fill(isPrime, true);
 6     isPrime[0] = isPrime[1] = false;
 7     for (int i = 2; i < Math.sqrt(num); i++) {
 8         if (isPrime[i])
 9             for (int j = i*i; j <= num; j += i)
10                 isPrime[j] = false;
11     }
12     int count = 0;
13     for (boolean k : isPrime) {
14         if (k)
15             count++;
16     }
17     System.out.println(num + "以内的素数有" + count + "个");
18 }

测试查找100000以内的质数速度对比:

 1 public static void main(String[] args) {
 2     int num = 100000;
 3     long startTime = System.currentTimeMillis();
 4     calPrimeByNormal(num);
 5     long endTime = System.currentTimeMillis();
 6     System.out.println("普通法查找程序运行时间:" + (endTime - startTime) + "ms");
 7     System.out.println();
 8     startTime = System.currentTimeMillis();
 9     calPrimeBySieve(num);
10     endTime = System.currentTimeMillis();
11     System.out.println("埃拉托斯特尼筛法查找程序运行时间:" + (endTime - startTime) + "ms");
12 }

输出结果:

正在普通法查找 100000 以内的素数...
100000以内的素数有9592个
普通法查找程序运行时间:623ms

正在以埃拉托斯特尼筛法查找 100000 以内的素数...
100000以内的素数有9592个
埃拉托斯特尼筛法查找程序运行时间:3ms

测试查找1000000以内的质数速度对比输出结果:

正在普通法查找 1000000 以内的素数...
1000000以内的素数有78498个
普通法查找程序运行时间:51197ms

正在以埃拉托斯特尼筛法查找 1000000 以内的素数...
1000000以内的素数有78498个
埃拉托斯特尼筛法查找程序运行时间:20ms

可见,查找速度提升很明显。


 

五、为什么外层循环只筛到 √n?

 

  • 若 x=a×b,,且 x ≤ n

  • 那么至少有一个因子满足 a ≤ √n

  • 所以:

    • 如果一个数在 √n 之前没被筛掉

    • 那么它一定是质数

因此,外层循环只需要进行到 √n。

六、为什么从 i² 开始筛?

以当前质数 i 为例:

  • 小于 i^2 的倍数:

    • 2i,3i,4i,…

  • 这些数在之前:

    • 已经被更小的质数筛掉了
      (如 3×5=15,会在筛 3 时被处理)

所以:

    • 从 i^2 开始筛既正确又高效

 

posted @ 2026-01-03 15:55  ywaanig  阅读(11)  评论(0)    收藏  举报