判断素数及其算法优化

首先,我们要清楚什么是素数?

素数又称质数,一个大于1的自然数,除了1和它本身外,不能被其他自然数整除,换句话说就是该数除了1和它本身以外不再有其他的因数;否则称为合数

根据素数的定义,我们可以写成出判断一个数是不是素数的算法。

    /**
     * 判断是否是素数
     *
     * @param n 目标数
     * @return true:是素数; false:不是素数
     */
    public static boolean isPrime(int n) {
        // 1 不是素数
        if (n <= 1) {
            return false;
        }
        // 由于在找 n 的因数时,只需要除到 n 开根号,所以只需 i*i<n 即可
        for (int i = 2; i * i < n; i++) {
            // 只要能被 i 整除,则返回 0
            if (n % i == 0) {
                return false;
            }
        }
        return true;
    }

我们知道如何判断一个数是不是素数后,就容易在给定的范围里寻找素数了。

不过,上面的判断素数的算法,在大范围内筛选素数的效率不是最高的。下面介绍一种Eratosthenes(埃拉托斯特尼)算法来进行素数的筛选,它的效率要高的多。

 

(1)先把1删除(1既不是质数也不是合数)

(2)读取队列中当前最小的数2,然后把2的倍数删去

(3)读取队列中当前最小的数3,然后把3的倍数删去

(4)读取队列中当前最小的数5,然后把5的倍数删去

.......

(n)读取队列中当前最小的状态为true的数n,然后把n的倍数删去

 

    /**
     * Eratosthenes算法(用于筛选素数)
     *
     * @param primes 标记素数的数组
     */
    private static void Eratosthenes(boolean[] primes) {
        // 数组的长度
        int length = primes.length;

        // 初始化数组,标志 true 代表是素数
        for (int i = 2; i < length; i++) {
            primes[i] = true;
        }

        for (int i = 2; i * i < length; i++) {
            // 筛选素数
            if (primes[i]) {
                for (int j = 2 * i; j < length; j++) {
                    // 不是素数,则继续筛选
                    if (!primes[j]) {
                        continue;
                    }
                    // 如果数 j 能被整除,则不是素数
                    if (j % i == 0) {
                        primes[j] = false;
                    }
                }
            }
        }
    }

下面我们使用分别上面的算法,传入一个测试用例来比较两个算法筛选素数的效率。

(1)使用Eratosthenes算法

    /**
     * 使用 Eratosthenes 算法寻找num以内的素数
     *
     * @param num 目标数
     */
    public static void selectPrimesByEratosthenes(int num) {
        // 定义保存素数的数组
        boolean[] primes = new boolean[num + 1];
        //统计素数个数
        int count = 0;
        // 调用 Eratosthenes 算法,筛选素数
        Eratosthenes(primes);
        // 遍历出num内的所有素数
        for (int i = 2; i <= num; i++) {
            if (primes[i]) {
                count++;
                System.out.println(i);
            }
        }
    }

 

测试代码:


    public static void main(String[] args) {
        // 寻找100000以内的素数
        int n = 100000;
        long start_time = System.currentTimeMillis();
        selectPrimesByEratosthenes(n);
        long end_time = System.currentTimeMillis();
        System.out.println("selectPrimesByEratosthenes:" + (double) (end_time - start_time) + " ms");

    }

(2)使用一般算法

    /**
     * 使用一般算法寻找素数
     *
     * @param num
     */
    public static void selectPrimeByGenerate(int num) {
        for (int i = 2; i <= num; i++) {
            if (isPrime(i)) {
                System.out.println(i);
            }
        }
    }

测试代码:

    public static void main(String[] args) {
        // 寻找100000以内的素数
        int n = 100000;
        long start_time = System.currentTimeMillis();
        selectPrimesByGenerate(n);
        long end_time = System.currentTimeMillis();
        System.out.println("selectPrimesByGenerate:" + (double) (end_time - start_time) + " ms");

    }

比较时间:(这里的时间还加上了打印素数的时间)

所以,当在大范围内筛选素数时,Eratosthenes算法效率要高的多。

 

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值