计算素数的改进算法

1 篇文章 0 订阅
1 篇文章 0 订阅

闲来无事,突然想起某群的加入条件是计算第5千万个素数是多少,如果按照素数定义来写程序,起码要跑好几个小时,所以观察了一下素数的规律,对计算方法进行了优化

  1. 话不多说,直接上代码

import java.util.ArrayList;
import java.util.Date;

/**
 * Created by dlh on 2020/4/27.
 */
public class test {
    /**
     * 原始筛选素数的方法
     * @param num 遍历范围
     * @return 当前范围类所有的素数
     */
    public static ArrayList<Integer> getSS(Integer num){
        Date startDate = new Date();
        ArrayList array = new ArrayList<Integer>();
        int i,j;
        for (i=2;i<=num;i++){ //外循环进行遍历素数范围
            for(j=2;j<i;j++) //内循环用于判断外循环的值是否为素数
                if(i%j==0) //判断在1-i之间是否存在能让i整除的数
                    break; //如果存在就代表,不是素数,7a686964616fe78988e69d8331333433623163反之则是
            if (j==i){ //如果j==i,则证明在1-i之间没有数能整除i,说明i是一个素数
                array.add(i); //将i存放进数组
            }
            else
                continue; //如果不相等,则继续外循环下一个数
        }
        Date endDate = new Date();
        long runtime = startDate.getTime()-endDate.getTime();
        System.out.println("原始方法用时时间"+runtime);
        return array;
    }

    /**第二步优化,使用ArrayList存在类型转换的开销
     * @param num 遍历范围
     * @return 当前范围类所有的素数
     */
    public static ArrayList<Integer> getSS2(Integer num){
        Date startDate = new Date();
        ArrayList array = new ArrayList<Integer>();//素数数组
        array.add(2);
        int i,j;
        for (i=2;i<=num;i++){ //外循环进行遍历素数范围
            for(j=0;j<array.size();j++) { //内循环用于判断外循环的值是否为素数
                Integer cs = (Integer) array.get(j);
                if (i % cs == 0) //判断在1-i之间是否存在能让i整除的数
                    break; //如果存在就代表,不是素数
                if ( j == (array.size()-1) ) { //除到最后一个数了,还没有被除断,则为素数
                    array.add(i); //将i存放进数组
                } else
                    continue; //如果不相等,则继续外循环下一个数
            }
        }
        Date endDate = new Date();
        long runtime = endDate.getTime()-startDate.getTime();
        System.out.println("改进方法用时时间"+runtime);
        return array;
    }

    /** 第三步优化,直接采用int数组,减少类型转换开销
     * @param num 需要获取素数的个数
     * @return 指定个数的 素数数组
     */
    public static int[] getSS3(Integer num){
        Date startDate = new Date();
        int[] array = new int[num];//素数数组
        int dq_index = 1;//初始下标
        array[0]=2;//默认第一个元素
        int i,j;
        for (i=2;i<=Integer.MAX_VALUE;i++){ //外循环进行遍历素数范围
            if (dq_index==num) break; //当数组到达指定长度时,退出循环
            for(j=0;j<dq_index;j++) { //内循环用于判断外循环的值是否为素数
                int cs = array[j];
                if (i % cs == 0) //判断在1-i之间是否存在能让i整除的数
                    break; //如果存在就代表,不是素数
                if ( j == (dq_index-1) ) { //除到最后一个数了,还没有被除断,则为素数
                    array[dq_index]=i; //将i存放进数组
                    dq_index++;//数组有效长度自增
                } else
                    continue; //如果不相等,则继续外循环下一个数
            }
        }
        Date endDate = new Date();
        long runtime = endDate.getTime()-startDate.getTime();
        System.out.println("筛选的最大值:"+i);
        System.out.println("========================");
        System.out.println("改进方法用时时间"+runtime);
        return array;
    }

    public static int[] getSS4(Integer num){
            long start = System.currentTimeMillis();
            int[] array = new int[num];//素数数组
            int dq_index = 2;//初始下标
            array[0]=2;//默认第一个元素
            array[1]=3;//默认第一个元素
            int i,j;
            for (i=3;i<=Integer.MAX_VALUE;i+=2){ //外循环进行遍历素数范围
                if (dq_index==num) break; //当数组到达指定长度时,退出循环
                for(j=0;j<dq_index;j++) { //内循环用于判断外循环的值是否为素数
                    int cs = array[j];
                    if (i % cs == 0) //判断在1-i之间是否存在能让i整除的数
                        break; //如果存在就代表,不是素数
                    if ( j == (dq_index-1) ) { //除到最后一个数了,还没有被除断,则为素数
                        array[dq_index]=i; //将i存放进数组
                        dq_index++;//数组有效长度自增
                    } else
                        continue; //如果不相等,则继续外循环下一个数
                }
            }
            Date endDate = new Date();
            long runtime = System.currentTimeMillis() - start;
            System.out.println("筛选的最大值:"+i);
            System.out.println("========================");
            System.out.println("改进方法用时时间"+runtime);
            return array;
        }

    public static void main(String[] args) {
        int num = 500000;
//        List a1 = getSS(num);
//        System.out.println(a1.size());
        ArrayList a2 = getSS2(7368788);
        Integer aLength = a2.size();
        Integer lastSS = (Integer) a2.get((aLength-1));
        System.out.println("素数个数:"+aLength+"======最后一个素数:"+lastSS);
//        int[] a2 = getSS3(num);
//        Integer aLength = a2.length;
//        Integer lastSS = a2[aLength-1];
//        System.out.println("素数个数:"+aLength+"======最后一个素数:"+lastSS);

    }
}

在2~1百万数字计算用时对比中,基本能提高10倍的性能,计算数字越多,性能提升越明显;

运算结果如下

原始方法用时时间-112538
78498
改进方法用时时间-13839
78498

78498为素数个数,计算结果也完全一致

方法2和方法3运行结果对比

  1. 方法2运行结果

改进方法用时时间574461
素数个数:500000======最后一个素数:7368787

    2.方法3运行结果

筛选的最大值:7368788
========================
改进方法用时时间468286
素数个数:500000======最后一个素数:7368787

减少类型转换开销之后,同样从2~7368788数字之间查找,也能提示100s的速度;

3.方法4运行结果

筛选的最大值:7368789
========================
改进方法用时时间183045
素数个数:500000======最后一个素数:7368787

 所有素数都是奇数,所以方法四就将循环步进改成了2,结果耗时又减少了60%多

总结:所有大于1的整数,只要不能被比自身小的素数整除,那么这个数也是素数(并且素数一定是奇数);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值