Java学习笔记 第六天 质数查找与较大整数的质数判断

今天放假返乡,忙了一天,晚上9点多才摸到电脑,,不说废话了看总结和代码吧:

总结:

由于今天依旧是对一些简单算法的调试与改造,不会总结太多。今天主要有两个算法,一个是筛法求[0, rightMargin]内的所有质数,一个是费马小定理快速判断质数,对于这些算法,我的解释肯定没有专业搞算法的大佬们清晰,如果有不会的朋友们请自行csdn~我在这里只展示这些算法的Java写法:

算法代码部分:

一,求区间内质数:

1.埃氏筛:

        非线性,但也非常快了,原理是用基底素数去筛它们的倍数

public static void EhrlichSieve(int rightMargin){//埃氏筛
            if(rightMargin < 2) {
                System.out.println("这个区间内没有质数!");
                return;
            }
            System.out.println("0 到 " + rightMargin + " 的质数有:");
            boolean[] stateArr = new boolean[rightMargin + 1];
            for(int i = 2; i <= rightMargin; i++){
                if(!stateArr[i]){
                    System.out.print(i + " ");
                    for(int j = i; j <= rightMargin; j += i){
                        stateArr[j] = true;
                    }
                }
            }
        }

2.欧拉筛:

        线性筛,非常快(但在某些题里依然不能用)。原理是用未被筛掉的合数乘到是它因子的素数,将得到的所有乘积全部筛掉,这些乘积是用来弥补其他素数筛漏的部分,然后再乘以第一个是它因子的素数,得到下一阶为其倍数的合数,以此类推;同时素数与素数相乘也达到了互相补全的效果,最后会没有重复的把区间内所有数都筛一遍,因此也叫线性筛。

public static void EulerSieve(int rightMargin){//欧拉筛(线性筛)
            if(rightMargin < 2) {
                System.out.println("这个区间内没有质数!");
                return;
            }
            System.out.println("0 到 " + rightMargin + " 的质数有:");
            boolean[] stateArr = new boolean[rightMargin + 1];
            ArrayList<Integer>primeArr = new ArrayList<>();
            for(int i = 2; i <= rightMargin; i++){
                if(!stateArr[i]) {//当前数有没有被过滤掉(是否为质数)
                    primeArr.add(i);//如果是质数,放入数组备用
                }
                for(int j = 0; j <= primeArr.toArray().length; j++){//从2开始,将没有过滤掉的数与已有质数相乘得到其倍数
                    if(primeArr.get(j) * i > rightMargin){//防止越界
                        break;
                    }
                    stateArr[primeArr.get(j) * i] = true;//过滤掉当前倍数
                    //只让合数乘到为其因子的第一个质数,补充其他质数漏乘的同时获得下一阶倍数同时防止出现乘积重复
                    if(i % primeArr.get(j) == 0){
                        break;
                    }
                }
                if(!stateArr[i]) {
                    System.out.print(i + " ");
                }
            }
        }

二,快速判断long范围内整数是否为质数:

费马小定理+二次探测优化:

        这个内容太多了,,建议直接csdn或去看相关的算法课,我就不多解释了

static class JudgeLargePrimer{//判断一个数是否为质数(long 内)
        //以下为费马小定理及其二次探测的优化算法
        private static boolean flag;
        private static long gcd(long a, long b){
            if(b == 0) return a;
            return gcd(b, a % b);
        }
        private static long fastMul(long x, long y, long mod){
            if(y == 1) return x % mod;
            if((y & 1) > 0) return ((x % mod) * fastMul(x, y - 1, mod)) % mod;
            long u = fastMul(x, y >> 1, mod);
            long v = (u * u) % mod;
            if(v == 1){
                if(u != 1 && u != mod - 1){
                    flag = false;
                }
            }
            return v;
        }
        public static boolean FermatSmallTheorem(long x){
            if(x <= 1) return true;
            int correctionTimes = 30;
            flag = true;
            while(correctionTimes-- > 0){
                Random random = new Random();
                long sampleData = (long) random.nextInt() % 10000 * random.nextInt() + 1;
                while(gcd(sampleData, x) != 1){
                    if(sampleData < x || sampleData % x != 0){
                        return false;
                    }
                    sampleData = (long) random.nextInt() % 1000 * random.nextInt() + 1;
                }
                if(fastMul(sampleData, x - 1, x) != 1 || !flag) return false;
            }
            return true;
        }
    }

测试输出:

 

 这里稍微提一下,费马小定理的逆定理需要随机数辅助来判断,有概率错误,不过加上二次探测优化后概率小的离谱,最大不超过4^-1000(4的负1000次方),所以放心用,,

 完整的调试代码:

/**
 * @author 阿白
 * @version v1.8
 * 希望毕业能直接找到工作,,,
 * */
import java.util.*;
public class HelloWorld {
    public static void main(String[] a) {
        PrimeTest.shifterWayFindPrimeTest();
        PrimeTest.judgeBigNumberIsPrime();
    }
}
class PrimeTest{
    public static void shifterWayFindPrimeTest(){
        Scanner sc = new Scanner(System.in);
        System.out.println("埃氏筛:");
        System.out.print("请输入要找质数的右边界:");
        int rightMargin1 = sc.nextInt();
        PrimerArithmetic.FindSectionPrimer.EhrlichSieve(rightMargin1);
        System.out.println("\n欧拉筛:");
        System.out.print("请输入要找质数的右边界:");
        int rightMargin2 = sc.nextInt();
        PrimerArithmetic.FindSectionPrimer.EulerSieve(rightMargin2);
    }
    public static void judgeBigNumberIsPrime(){
        Scanner sc = new Scanner(System.in);
        System.out.print("\n请输入判断的大整数(2E18以内),按Ctrl + D 结束输入: ");
        while(sc.hasNextLong()){
            long targetNumber = sc.nextLong();
            boolean sign = PrimerArithmetic.JudgeLargePrimer.FermatSmallTheorem(targetNumber);
            if(sign){
                System.out.println("No");
            }else{
                System.out.println("Yes");
            }
            System.out.print("\n请输入判断的大整数(9E18以内): ");
        }
    }
}
class PrimerArithmetic{
    static class FindSectionPrimer{//找范围内的所有质数
        public static void EhrlichSieve(int rightMargin){//埃氏筛
            if(rightMargin < 2) {
                System.out.println("这个区间内没有质数!");
                return;
            }
            System.out.println("0 到 " + rightMargin + " 的质数有:");
            boolean[] stateArr = new boolean[rightMargin + 1];
            for(int i = 2; i <= rightMargin; i++){
                if(!stateArr[i]){
                    System.out.print(i + " ");
                    for(int j = i; j <= rightMargin; j += i){
                        stateArr[j] = true;
                    }
                }
            }
        }
        public static void EulerSieve(int rightMargin){//欧拉筛(线性筛)
            if(rightMargin < 2) {
                System.out.println("这个区间内没有质数!");
                return;
            }
            System.out.println("0 到 " + rightMargin + " 的质数有:");
            boolean[] stateArr = new boolean[rightMargin + 1];
            ArrayList<Integer>primeArr = new ArrayList<>();
            for(int i = 2; i <= rightMargin; i++){
                if(!stateArr[i]) {//当前数有没有被过滤掉(是否为质数)
                    primeArr.add(i);//如果是质数,放入数组备用
                }
                for(int j = 0; j <= primeArr.toArray().length; j++){//从2开始,将没有过滤掉的数与已有质数相乘得到其倍数
                    if(primeArr.get(j) * i > rightMargin){//防止越界
                        break;
                    }
                    stateArr[primeArr.get(j) * i] = true;//过滤掉当前倍数
                    //只让合数乘到为其因子的第一个质数,补充其他质数漏乘的同时获得下一阶倍数同时防止出现乘积重复
                    if(i % primeArr.get(j) == 0){
                        break;
                    }
                }
                if(!stateArr[i]) {
                    System.out.print(i + " ");
                }
            }
        }
    }
    static class JudgeLargePrimer{//判断一个数是否为质数(long 内)
        //以下为费马小定理及其二次探测的优化算法
        private static boolean flag;
        private static long gcd(long a, long b){
            if(b == 0) return a;
            return gcd(b, a % b);
        }
        private static long fastMul(long x, long y, long mod){
            if(y == 1) return x % mod;
            if((y & 1) > 0) return ((x % mod) * fastMul(x, y - 1, mod)) % mod;
            long u = fastMul(x, y >> 1, mod);
            long v = (u * u) % mod;
            if(v == 1){
                if(u != 1 && u != mod - 1){
                    flag = false;
                }
            }
            return v;
        }
        public static boolean FermatSmallTheorem(long x){
            if(x <= 1) return true;
            int correctionTimes = 30;
            flag = true;
            while(correctionTimes-- > 0){
                Random random = new Random();
                long sampleData = (long) random.nextInt() % 10000 * random.nextInt() + 1;
                while(gcd(sampleData, x) != 1){
                    if(sampleData < x || sampleData % x != 0){
                        return false;
                    }
                    sampleData = (long) random.nextInt() % 1000 * random.nextInt() + 1;
                }
                if(fastMul(sampleData, x - 1, x) != 1 || !flag) return false;
            }
            return true;
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿白|

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值