JAVA取质数(素数)算法优化

质数(prime number)又称素数,有无限个。质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数。也可以理解为:这个数与除1之外小于它的数取余不为0,则这个数为质数。

案例

我们在学习或者面试过程中经常会问:输出100以内的所有质数

那我们简单整理一下思路:
1. 定义整型变量,i 和 j
2. 利用for循环的嵌套一个一个判断是否i能否被j整除(i % j == 0)
3. 如果能被整除,也就是说 i 不是质数
4. 定义一个标识,( isFlag = true), 如果这个标识没有被改变,这个数就是质数
5. 输出这个数,然后通过外循环进行判断下一个 i 是不是质数
代码如下:
public static void main(String[] args) {
     
    boolean isFlag = true;
    for (int i = 2; i < 100; i++) {
     
        for (int j = 2; j < i; j++) {
     
            if (i % j == 0) {
     
                isFlag = false;
            }

        }
        if (isFlag) {
     
            System.out.println(i);
        }
        isFlag = true;
    }
}

【拓展】这种方法对于查找100以内的质数来说还是可以的,但是如果将100改成100000呢?或者更大的数呢?那么这种方式还是否同样好用呢?于是我做了如下尝试,将100改成10000,并在代码中添加时间计数器,看最后程序运行完毕需要的时间是多少。
demo1:

public static void main(String[] args) {
     
    boolean isFlag = true;
    long start = System.currentTimeMillis();//获取系统当前累计毫秒数
    for (int i = 2; i < 100000; i++) {
     
        for (int j = 2; j < i; j++) {
     
            if (i % j == 0) {
     
                isFlag = false;
            }

        }
        if (isFlag) {
     
            System.out.println(i);
        }
        isFlag = true;
    }
    long end = System.currentTimeMillis();//获取系统当前累计毫秒数

    System.out.println("所花费的时间为" + (end - start) + "毫秒");
}

所花费的时间为13919毫秒。 (可以看到,运行效率就低了很多,当然代码运行效率与硬件也有关)

那我们该如何优化呢?

优化一

可以在if条件里面增加break,当能被整除,则不用继续循环下去了,代码如下:

public static void main(String[] args) {
     
    boolean isFlag = true;
    long start = System.currentTimeMillis();//获取系统当前累计毫秒数
    for (int i = 2; i < 100000; i++) {
     
        for (int j = 2; j < i; j++) {
     
            if (i % j == 0) {
     
                isFlag = false;
                 break; // 优化一 :满足条件跳出循环。只对本身非质数的自然数是有效的
            }

        }
        if (isFlag) {
     
            System.out.println(i);
        }
        isFlag = true;
    }
    long end = System.currentTimeMillis();//获取系统当前累计毫秒数

    System.out.println("所花费的时间为" + (end - start) + "毫秒");
}

所花费的时间为1136毫秒,这个时候就可以看到运行效率快了很多,但这还不是最优解法,可以看一下优化二。

优化二

上面我们使用break优化,满足了对本身非质数的自然数的优化,那是不是可以对本身是质数的在做一次优化呢,我们可以使用 Math.sqrt(i) 代码示例:

public static void main(String[] args) {
     
    boolean isFlag = true;
    long start = System.currentTimeMillis();//获取系统当前累计毫秒数
    for (int i = 2; i < 100000; i++) {
     
        //优化二: 对本身是质数的自然数是有效的
        for (int j = 2; j <= Math.sqrt(i); j++) {
     
            if (i % j == 0) {
     
                isFlag = false;
                break; // 优化一 :满足条件跳出循环。只对本身非质数的自然数是有效的
            }

        }
        if (isFlag) {
     
            System.out.println(i);
        }
        isFlag = true;
    }
    long end = System.currentTimeMillis();//获取系统当前累计毫秒数

    System.out.println("所花费的时间为" + (end - start) + "毫秒");
}

所花费的时间为53毫秒。这就明显快了很多了

我们也可以做一下其他的优化,如 System.out.println(i) 也是比较消耗性能的,可以将代码注释,替换成累加count:

public static void main(String[] args) {
     
        boolean isFlag = true;
        int count = 0;
        long start = System.currentTimeMillis();//获取系统当前累计毫秒数
        for (int i = 2; i < 100000; i++) {
     
            //优化二: 对本身是质数的自然数是有效的
            for (int j = 2; j <= Math.sqrt(i); j++) {
     
                if (i % j == 0) {
     
                    isFlag = false;
                    break; // 优化一 :满足条件跳出循环。只对本身非质数的自然数是有效的
                }

            }
            if (isFlag) {
     
                count++;
//                System.out.println(i);
            }
            isFlag = true;
        }
        long end = System.currentTimeMillis();//获取系统当前累计毫秒数

        System.out.println("100000以内的质数个数为" + count + "个");
        System.out.println("所花费的时间为" + (end - start) + "毫秒");
    }

100000以内的质数个数为9592个
所花费的时间为12毫秒

这个时候赶脚自己还要学习的很多呀!!!

你可能感兴趣的:(JAVA,面试宝典,算法,java,面试,输出100以内的所有质数)