三大筛法Java版讲解(暴力筛法、埃氏筛法、欧拉筛法)

素数的定义

三分筛法主要针对于素数的判断,所以应先了解素数的定义

质数又称素数。一个 大于1的自然数,除了 1它自身 外,不能被其他自然数整除的数叫做质数;否则称为合数(规定1既不是质数也不是合数)

比如:2 、3 、5 、7 、11 、13 ······都属于素数

暴力筛法

直接一个个判断,没什么算法可言

  • 优点:代码简单,通俗易懂,容易上手
  • 缺点:耗费内存,运行缓慢,容易超时

下面是计算出 2 ~40000 之间素数个数的代码:

public class Main {
    public static void main(String[] args) {
        long start = System.currentTimeMillis(); //暴力筛法开始前记录当时的时间戳
        int count=0;
        for (int i = 2; i <= 40000; i++) {  //求出 2 ~ 40000 的素数,数据大一点可以看出效率
            if (isPrime(i)) {  //如果是素数的话
                count++;
            }
        }
        long end = System.currentTimeMillis();  //暴力筛法结束后记录当时的时间戳
        System.out.println(count);
        System.out.println(end - start);  //相减得到该算法所需要的时间 约为 2.5ms
    }

    public static boolean isPrime(int i) {  //其中 i 是要判断是否为素数的数字

    //下面 for 循环中没有用 Math 的 sqrt 是因为调用 Math.sqrt() 的时间 大于 两个数相除的时间

    //for 循环中不是 j * j <= i 是因为这样子容易溢出整数 int 范围,而且 j 是从 2 开始的,不用担心被除数不能为 0

        for (int j = 2; j <= i / j; j++) {  //从 2 开始找,找到根号i 为止
            if (i % j == 0) {   //如果其中 i 可以被整除,说明 i 不是素数,就直接返回 false
                return false;
            }
        }
        return true;  //到这里表明 i 是素数,返回 true
    }
}

耗时约为 2.5 ms

埃氏筛法

要得到自然数n以内的全部素数,必须把不大于的所有素数的倍数剔除,剩下的就是素数。

详细步骤: 
  1. 列出2以后的所有序列:

    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  2. 标出序列中的第一个素数,也就是2,序列变成:

    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  3. 将剩下序列中,划掉2的倍数,序列变成:

    2 3 5 7 9 11 13 15 17 19 21 23 25
  4. 如果这个序列中最大数小于最后一个标出的素数的平方,那么剩下的序列中所有的数都是素数,否则回到第二步。

  5. 本例中,因为25大于2的平方,我们返回第二步:

  6. 剩下的序列中第一个素数是3,将主序列中3的倍数划掉,主序列变成:

    2 3 5 7 11 13 17 19 23 25
  7. 我们得到的素数有:2,3

  8. 25仍然大于3的平方,所以我们还要返回第二步:

  9. 序列中第一个素数是5,同样将序列中5的倍数划掉,主序列成了:

    2 3 5 7 11 13 17 19 23
  10. 我们得到的素数有:2,3,5 。

  11. 因为23小于5的平方,跳出循环.

结论:2到25之间的素数是:2 3 5 7 11 13 17 19 23。

下面是计算出 2 ~40000 之间素数个数的代码:

​
​
public class Main {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();  //埃氏筛法开始前记录当时的时间戳
        int count = 0;
        boolean[] isPrime = new boolean[40001];  //boolean默认值为 false,其中 false代表是素数,true 代表的是合数
        for (int i = 2; i < 40001; i++) {
            if (!isPrime[i]) {  //如果是素数的话
                count++;
                for (int j = i * i; j < 40001; j += i) {  //将 j 赋值为 i * i,每次都让 j+=i 这样子 j 永远是 i 的倍数
                    isPrime[j] = true;  //标记合数 j
                }
            }
        }
        long end = System.currentTimeMillis();  //埃氏筛法结束后记录当时的时间戳
        System.out.println(count);
        System.out.println(end - start);  //相减得到该算法所需要的时间 约为 1ms
    }
}

​

​

耗时约为 1 ms

欧拉筛法

由于所有合数都有一个最小质因子,所以在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。

  • 优点:效率高
  • 缺点:过程难理解,数据太小效率不高

算法步骤:

  1. 2 到某数N之问的自然数列出来,标准格式为:2,3,4,......,N
  2. 2 设为第一个素数
  3. 2 的倍数全部剔除
  4. 到下一个未被剔除的数,将其设为第二个素数
  5. 该数的倍数全部剔除
  6. 重复第1、5步,直到所有小于某数的素数都被找出来

下面是计算出 2 ~40000 之间素数个数的代码:

public class Main {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();  //埃氏筛法开始前记录当时的时间戳
        int count = 0;
        // 建立一个bool类型的数组,以下标为要判断的数字 以该下标的值为素数的标志,
       //若i是素数 则 isPrime[i]=false
        boolean[] isPrime = new boolean[40000];
        isPrime[0] = isPrime[1] = true;  //数字0和1都不是素数,所以赋true

        int[] Prime = new int[40000];  //存放素数的数组
        int t = 0;
        Prime[t++] = 2;//把2放进素数表
        for (int i = 2; i < 40000; i++) {
            if (!isPrime[i]) {  //若当前数是素数
                Prime[t++] = i;  //则存入素数数组
                count++;

            }

            for (int j = 0; j < t && Prime[j] * i < 40000; j++) {
                isPrime[i * Prime[j]] = true;
                if (i % Prime[j] == 0)
                    break;  //避免重筛,使得程序更有效率
            }
        }
        long end = System.currentTimeMillis();  //欧拉筛法结束后记录当时的时间戳
        System.out.println(count);
        System.out.println(end - start);  //相减得到该算法所需要的时间 约为 2ms
    }
}

 耗时约为 2 ms

总结

因为该40000太小了,不能体现欧拉筛法的效率,当数据足够大时,可以更好的展现欧拉筛法的高效性。比如当计算 2 ~ 10000000 时,暴力算法耗时 2834 ms,而使用欧拉筛法耗时 65 ms。但对于埃氏筛法来说不行,因为其中有个for 循环 int j = i * i,此时如果 i 太大 (i 大于46340)的话,会超过 j (int)的上限。所以如果数据量较小时(小于50000),建议直接暴力筛法,如果数据量过大就采用欧拉筛法。

帮助

如果关于欧拉筛法还有困惑的,不知道是怎么进行的,可以去哔哩哔哩观看视频,效果会更好

推荐b站:秋水共长天一色566  其中的《欧拉筛,几行就行,一次就好》

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值