用输出100000以内的质数(或素数)体会算法对程序的优化

一、先看看“输出100以内的质数”的算法及对其的理解

(一)计算方法1:
package test;

public class PrimeNumberTest1 {

    public static void main(String[] args) {
        int number=0;

        for(int i=2;i<=100;i++){//遍历100以内的自然数;

            for (int j=2;j<i;j++){//遍历从2到i-1的数;
                if(i%j==0){//质数换句话说就是从2到i-1都没有i的约数;
                    number++;
                }

            }

            if(number==0){
                System.out.print(i+",");//输出质数
            }
            number=0;//重置number;
        }

    }

}
输出结果:

如何来理解这个算法呢?看下图

1. int number=0 相当于定制一件马甲,谁是质数就直接给谁穿上,就可以从质数出口出来;如果不是质数,就在马甲上打X从合数出口出来。从出口出来后,如果马甲上没有X就直接给下一个等待进入的数字,如果有X就涂掉X给下一个数字。这个涂掉X 的过程就是重置number的过程。
2.for(int i=2;i<=100;i++)遍历从2到100以内的自然数,相当于等待甄别的数字。
3.for(int j=2;j<i;j++)遍历从2到i-1以内的自然数。
4、if(i%j==0){number++;}  用每一个需要甄别的数字去取模2到i-1的自然数,如果余数等于0,说明该数除了1和它本身之外还有约数。这时候改变number的值就相当于在马甲上打X。有些人有疑问,为什么不在这里把条件改为(i%j!=0)然后直接输出“i”呢?答案是不能这样输出。举个例子:当i=9,j=2是,满足i%j!=0,但是9不是质数。要满足所有从2到小于本身的整数都不整除才是质数。
5、如果没有重置number,number以后都不是0,相当于后面的数字拿到的马甲都是打X的,就无法甄别是否为质数了。
6、如果把int number=0换一个位置,代码如下:
package test;

public class PrimeNumberTest1 {

    public static void main(String[] args) {
        

        for(int i=2;i<=100;i++){//遍历从2到100以内的自然数;
            int number=0;
            for (int j=2;j<i;j++){//遍历从2到i-1的数;
                if(i%j==0){//质数换句话说就是从2到i-1都没有i的约数;
                    number++;
                }

            }

            if(number==0){
                System.out.print(i+",");//输出质数
            }
           
        }

    }

}
 运行结果是一样的:

 但是有一点不一样,外层for循环每执行一次,number就赋值0一次,相当于给每一个等待甄别的数字都发了一件初始马甲,出来的数字不用再把身上的马甲给下一位。这种方法的运行速度其实较第一种是要慢一下的。

二、在看一看“输出100000以内质数的个数”体会算法改变对程序性能的优化

(一)算法一:代码如下

package test;

public class PrimeNumber {
    //输出100000以内的质数的个数

    public static void main(String[] args) {
        int number=0;
        int count=0;
        long start=System.currentTimeMillis();//程序开始时当前时间;
        for(int i=2;i<=100000;i++){//遍历100000以内的自然数;

            for (int j=2;j<i;j++){//遍历从2到i-1的数;
                if(i%j==0){//质数换句话说就是从2到i-1都没有i的约数;
                    number++;
                }

            }

            if(number==0){
                count++;//每满足质数的条件就记一个数;
            }
            number=0;//重置number;
        }
        long end=System.currentTimeMillis();//结束时当前时间;
        System.out.println("100000以内的质数个数为:"+count);
        System.out.println("程序花费时间为:"+(end-start));
    }

}

运行结果为:

这里用时16秒多,用时还是比较多的。我们看看算法二

(二)算法二:代码如下

package test;

public class PrimeNumber {
    //输出100000以内的质数的个数

    public static void main(String[] args) {
        int number=0;
        int count=0;
        long start=System.currentTimeMillis();//程序开始时当前时间;
        for(int i=2;i<=100000;i++){//遍历100000以内的自然数;

            for (int j=2;j<i;j++){//遍历从2到i-1的数;
                if(i%j==0){//质数换句话说就是从2到i-1都没有i的约数;
                    number++;
                    break;//只要遇到有约数就停止,没有必要把从2到小于该数的整数都算一遍
                }

            }

            if(number==0){
                count++;//每满足质数的条件就记一个数;
            }
            number=0;//重置number;
        }
        long end=System.currentTimeMillis();//结束时当前时间;
        System.out.println("100000以内的质数个数为:"+count);
        System.out.println("程序花费时间为:"+(end-start));
    }

}

 运行结果如下:

在number++后加了break,程序花费时间就少了很多,这里只用了1秒多。

(三)算法三:

package test;

public class PrimeNumber {
    //输出100000以内的质数的个数

    public static void main(String[] args) {
        int number=0;
        int count=0;
        long start=System.currentTimeMillis();//程序开始时当前时间;
        for(int i=2;i<=100000;i++){//遍历100000以内的自然数;

            for (int j=2;j<=Math.sqrt(i);j++){//遍历从2到i-1的数;
                if(i%j==0){//质数换句话说就是从2到i-1都没有i的约数;
                    number++;
                    break;//只要遇到有约数就停止,没有必要把从2到小于该数的整数都算一遍
                }

            }

            if(number==0){
                count++;//每满足质数的条件就记一个数;
            }
            number=0;//重置number;
        }
        long end=System.currentTimeMillis();//结束时当前时间;
        System.out.println("100000以内的质数个数为:"+count);
        System.out.println("程序花费时间为:"+(end-start));
    }

}

程序在内层循环for(int j=2;j<i;j++)这里改成了for(int j;j<=Math.sqrt(i);j++),相当于把遍历的范围变成了根号i,为什么这样可以呢。

 运行结果如下:

 这个时间大大的缩小了,大家从以上的案例体验到算法对程序的优化了吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值