Java工具类-素数类

引子

个人比较喜欢算法,在日常解题过程中,经常遇到各种跟素数有关的问题。为了方便未来使用,总结创建了素数工具类。

Prime类说明

Prime类用于处理素数相关问题,Prime类被设计为工具类,不允许创建实例,也不允许被继承,故以final修饰Prime类,并以private修饰默认构造器。

Prime类本身维护一个从2开始的素数列表(ArrayList),类初始化时,根据sInitPrimeListLength的值,初始素数列表长度为1000,在进行各种处理时会用到这个数组,特称由Prime类维护的素数数组为类列表。利用类列表,已经计算过的素数不会再重复计算,提高效率。

类列表衍生两个变量,一个是列表长度,即类列表维护的从2开始的素数的个数,可由函数getPrimeListLength()获得。另一个是已知最大素数,即类列表的最后一个元素,可由函数getMaxCheckedPrime()获得。这两个值在素数类内部被广泛使用。

Prime类常用的方法有以下几个:
1. int[] getPrimeArrayByLength(int length)
2. int[] getPrimeArrayBelow(int num)
3. int[] getPrimeArrayBetween(int startNum, int endNum)

Prime类提供判断是否为素数的方法:
1. boolean isPrime(int)
2. boolean isProbablePrime(String num, int certainty)
3. boolean isQuickPrime(int num)

Prime类还提供求最小公倍数和最大公约数的函数,以及其它方法,具体可以查看下面的函数列表。

函数列表

  • int[] getPrimeArray()
    将类列表中的素数转换为int数组返回
  • int[] getPrimeArray(int start,int end)
    将类列表中索引start至end的元素转换为int数组返回
  • int[] getPrimeArray(int length)
    将类列表中前length个素数转换为int数组返回
  • int getPrimeListLength()
    返回类列表中元素的个数
  • int getMaxCheckedPrime()
    返回类列表的最后一个元素
  • boolean isPrime(int)
    判断一个int整数是否为素数
  • boolean isProbablePrime(String num, int certainty)
    采用Miller-Rabin算法判断一个大整数是否为素数,可靠性为1-1/(2^certainty)
  • boolean isQuickPrime(int num)
    利用类列表快速判断num是否为素数
  • int[] getPrimeArrayByLength(int length)
    返回长度为length的素数数组
  • int[] getPrimeArrayBelow(int num)
    返回小于等于num的素数数组
  • int[] getPrimeArrayBetween(int startNum, int endNum)
    返回startNum与endNum之间的素数组成的数组
  • int getPrimeIndex(int num)
    返回num在类列表中的索引,找不到返回-1
  • int getPrimeIndex(int num, boolean isStrict)
    返回num在类列表中的索引,找不到时,如果isStrict为true,则返回小于num的第一个元素的索引
  • int binarySearch(int[] arr, int key)
    在数组arr中查找key,如果找到则返回索引,找不到返回-1
  • int binarySearch(int[] arr, int key, boolean isStrict)
    在数组arr中查找key,找不到时,如果isStrict为true,则返回小于num的第一个元素的索引
  • int Gcd(int a, int b)
    返回a和b的最大公约数,如果a<=0或b<=0,则返回0
  • int Gcd(int[] numArray)
    返回数组内所有整数的最大公约数
  • int Lcm(int a, int b)
    返回a,b的最小公倍数
  • int Lcm(int[] numArray)
    返回数组内所有整数的最小公倍数

git代码仓库地址

下面是java源代码。对这个素数类有什么建议的可以在评论区提,我也在努力完善它。
码云git地址:http://git.oschina.net/bedbed/Euler/

最新版的代码在git上面,可能不会在这里更新。

素数类源码

package stone.math;

import java.util.ArrayList;
import java.util.Iterator;
import java.lang.Math;
import java.math.BigInteger;

/*
 * Copyright (C) 2014-2016  Stone Chen
 * All rights reserved by  Stone Chen
 *
 *  Modification History:
 *  Date        Author      Version     Description
 *  -----------------------------------------------
 *  2016年9月13日     Stone Chen   1.0         [实现基本功能]
 *  2016年9月28日      Stone Chen 1.1         [添加判断大数是否为质数函数,调用BigInteger提供的方法]
 *  2016年10月27日   Stone Chen 1.2         [由维护数组改为维护集合]
 *
 */

/**
 * [功能说明]素数工具类,工具类具有私有构造器,不允许创建实例,提供各种静态方法
 */
public final class Prime {

    /** [初始化时生成的sPrimeArray长度] */
    private static final int sInitPrimeListLength = 1000;
    /** [从2开始的素数集合] */
    private static ArrayList<Integer> sPrimeList = new ArrayList<Integer>(sInitPrimeListLength);

    /**
     * 类初始化代码块
     */
    static {
        getPrimeArrayByLength(sInitPrimeListLength);
    }

    /**
     * 工具类的私有构造器
     */
    private Prime() {

    }

    /**
     * [功能说明] 将primeList转换为int数组
     * 
     * @return int数组
     */
    public static int[] getPrimeArray() {
        int[] primeArray = new int[getPrimeListLength()];
        for (int i = 0; i < primeArray.length; i++) {
            primeArray[i] = sPrimeList.get(i);
        }
        return primeArray;
    }

    /**
     * [功能说明] 将primeList的索引start至end的元素转换为int数组返回
     * 
     * @param start
     *            如果start < 0,那么start会被置为0
     * @param end
     *            如果end < start,那么end会被置为start
     * @return 素数数组
     */
    public static int[] getPrimeArray(int start, int end) {
        if (start < 0) {
            start = 0;
        }
        if (end < start) {
            end = start;
        }
        int length = end - start + 1;
        int[] primeArray = new int[length];
        for (int i = 0; i < length; i++, start++) {
            primeArray[i] = sPrimeList.get(start);
        }
        return primeArray;
    }

    /**
     * [功能说明] 返回从2开始的长度为length的素数数组
     * 
     * @param length
     * @return
     */
    public static int[] getPrimeArray(int length) {
        if (length < 1) {
            length = 1;
        }
        return getPrimeArray(0, length - 1);
    }

    /**
     * [功能说明] 返回维护的素数集合的长度
     * 
     * @return
     */
    public static int getPrimeListLength() {
        return sPrimeList.size();
    }

    /**
     * [功能说明] 返回素数集合的最后一个元素
     * 
     * @return
     */
    public static int getMaxCheckedPrime() {
        int listLength = getPrimeListLength();
        if (listLength > 0) {
            return sPrimeList.get(getPrimeListLength() - 1);
        }
        return 1;
    }

    /**
     * [功能说明]判断一个数是否为素数
     * 
     * @param num
     *            待判断的整数
     * @return num是素数返回true,否则返回false
     */
    public static boolean isPrime(int num) {
        boolean flag = true;
        if (num < 2) {
            return false;
        }
        for (int i = 2; i * i <= num; i++) {
            if (num % i == 0) {
                flag = false;
                break;
            }
        }
        return flag;
    }

    /**
     * [功能说明]采用Miller-Rabin算法判断一个大整数是否为素数,可靠性为1-1/(2^certainty)
     * 
     * @param num
     *            待判断的整数
     * @return 是素数返回true
     */
    public static boolean isProbablePrime(String num, int certainty) {
        BigInteger bigNum = new BigInteger(num);
        return bigNum.isProbablePrime(certainty);
    }

    /**
     * [功能说明]利用sPrimeList快速判断是否为素数
     * 
     * @param num
     *            待判断的整数
     * @return 是否为素数
     */
    public static boolean isQuickPrime(int num) {
        if (num > getMaxCheckedPrime()) {
            boolean flag = true;
            int i = 0;
            for (; i < getPrimeListLength() && sPrimeList.get(i) <= Math.sqrt(num); i++) {
                if (num % sPrimeList.get(i) == 0) {
                    flag = false;
                    break;
                }
            }
            if (i == getPrimeListLength()) {
                for (int n = getMaxCheckedPrime(); n <= Math.sqrt(num); n++) {
                    if (num % n == 0) {
                        flag = false;
                        break;
                    }
                }
            }
            return flag;
        }

        if (getPrimeIndex(num) == -1) {
            return false;
        }

        return true;
    }

    /**
     * [功能说明]返回长度为length的素数数组
     * 
     * @param length
     *            返回的数组长度
     * @return int素数数组
     */
    public static int[] getPrimeArrayByLength(int length) {
        // length<1则返回空数组
        if (length < 1) {
            return new int[] {};
        }
        // 如果length小于等于素数集合的长度,则将素数集合前length个元素转换为int数组返回
        if (length <= getPrimeListLength()) {
            return getPrimeArray(length);
        }
        // length大于素数集合长度情况的处理
        int count = getPrimeListLength();
        for (int num = getMaxCheckedPrime() + 1; count < length; num++) {
            if (isPrime(num)) {
                sPrimeList.add(num);
                count++;
            }
        }
        return getPrimeArray(length);
    }

    /**
     * [功能说明]返回num以下的素数数组,不包括num
     * 
     * @param num
     *            请求的素数数组上限
     * @return 素数数组
     */
    public static int[] getPrimeArrayBelow(int num) {
        if (num < 2) {
            return new int[] {};
        }

        // 如果num <= MaxCheckedPrime,则返回sPrimeList的子集的数组
        if (num <= getMaxCheckedPrime()) {
            int index = getPrimeIndex(num, true);
            return getPrimeArray(index + 1);
        }
        // 将大于MaxCheckedPrime小于num的素数加入list
        for (int n = getMaxCheckedPrime() + 1; n < num; n++) {
            if (isPrime(n)) {
                sPrimeList.add(n);
            }
        }
        return getPrimeArray(getPrimeListLength());
    }

    /**
     * [功能说明]返回startNum与endNum之间的素数数组,包括边界
     * 
     * @param startNum
     *            起点
     * @param endNum
     *            终点
     * @return 素数数组
     */
    public static int[] getPrimeArrayBetween(int startNum, int endNum) {
        // startNum>=endNum,如果startNum是素数,则返回单元素数组,否则返回空数组
        if (startNum >= endNum) {
            if (isPrime(startNum)) {
                return new int[] { startNum };
            } else {
                return new int[] {};
            }
        }
        // startNum<endNum,startNum <= sPrimeList的最后一个元素
        if (startNum <= getMaxCheckedPrime()) {
            int start = getPrimeIndex(startNum, true);
            if (start == -1 || sPrimeList.get(start) != startNum) {
                start++;
            }
            if (endNum <= getMaxCheckedPrime()) {
                int end = getPrimeIndex(endNum, true);
                return getPrimeArray(start, end);
            } else {
                for (int num = getMaxCheckedPrime() + 1; num <= endNum; num++) {
                    if (isPrime(num)) {
                        sPrimeList.add(num);
                    }
                }
                return getPrimeArray(start, getPrimeListLength() - 1);
            }
        }
        // startNum<endNum,startNum > sPrimeList的最后一个元素
        ArrayList<Integer> al = new ArrayList<>();
        for (int num = startNum; num <= endNum; num++) {
            if (isPrime(num)) {
                al.add(num);
            }
        }
        int[] primeArray = new int[al.size()];
        Iterator<Integer> it = al.iterator();
        int i = 0;
        while (it.hasNext()) {
            primeArray[i++] = it.next();
        }
        return primeArray;
    }

    /**
     * [功能说明]返回num在sPrimeList的索引,如果不存在则返回-1,用二分法查找
     * 
     * @param num
     *            待查找的整数
     * @return index 索引
     */
    public static int getPrimeIndex(int num) {
        return getPrimeIndex(num, false);
    }

    /**
     * [功能说明]返回num在sPrimeList的索引,如果不存在则返回-1,用二分法查找
     * 
     * @param num
     * @param isStrict
     *            是否在找不到时返回小于num的第一个元素的索引
     * @return 索引
     */
    public static int getPrimeIndex(int num, boolean isStrict) {
        int start = 0;
        int end = getPrimeListLength() - 1;
        while (start <= end) {
            int middle = (start + end) / 2;
            if (num < sPrimeList.get(middle)) {
                end = middle - 1;
            } else if (num > sPrimeList.get(middle)) {
                start = middle + 1;
            } else {
                return middle;
            }
        }
        // 若集合中找不到,是否返回小于key的最大数的索引
        if (isStrict) {
            int result = start > end ? end : -1;
            return result;
        }
        return -1;
    }

    /**
     * [功能说明]用二分法在数组arr中查找key,找到返回索引,返回-1
     * 
     * @param arr
     *            待搜索的数组
     * @param key
     *            关键字
     * @return 索引值
     */
    public static int binarySearch(int[] arr, int key) {
        return binarySearch(arr, key, false);
    }

    /**
     * [功能说明]用二分法在数组arr中查找key,找到返回索引,否则根据isStrict标志返回
     * 
     * @param arr
     *            待搜索的数组
     * @param key
     *            关键字
     * @param isStrict
     *            是否要求在找不到key时返回小于key的最大值的索引
     * @return 索引值
     */
    public static int binarySearch(int[] arr, int key, boolean isStrict) {
        int start = 0;
        int end = arr.length - 1;
        while (start <= end) {
            int middle = (start + end) / 2;
            if (key < arr[middle]) {
                end = middle - 1;
            } else if (key > arr[middle]) {
                start = middle + 1;
            } else {
                return middle;
            }
        }
        // 若数组中找不到,是否返回小于key的最大数的索引
        if (isStrict) {
            int result = start > end ? end : -1;
            return result;
        }
        return -1;
    }

    /**
     * [功能说明] 返回a和b的最大公约数,如果a<=0或b<=0,则返回0
     * 
     * @param a
     *            正整数a
     * @param b
     *            正整数b
     * @return 最大公约数
     */
    public static int Gcd(int a, int b) {
        if (a <= 0 || b <= 0) {
            return 0;
        }
        int remainder = 0;
        while ((remainder = a % b) != 0) {
            a = b;
            b = remainder;
        }
        return b;
    }

    /**
     * [功能说明] 求数组内所有整数的最大公约数
     * 
     * @param numArray
     *            正整数数组
     * @return 最大公约数
     */
    public static int Gcd(int[] numArray) {
        int gcd = numArray[0];
        for (int i = 1; i < numArray.length; i++) {
            gcd = Gcd(gcd, numArray[i]);
        }
        return gcd;
    }

    /**
     * [功能说明] 求a,b的最小公倍数
     * 
     * @param a
     *            正整数a
     * @param b
     *            正整数b
     * @return 最小公倍数
     */
    public static int Lcm(int a, int b) {
        if (a <= 0 || b <= 0) {
            return 0;
        }
        int gcd = Gcd(a, b);
        return a / gcd * b;
    }

    /**
     * [功能说明] 求数组内所有整数的最小公倍数
     * 
     * @param numArray
     *            正整数数组
     * @return 最小公倍数
     */
    public static int Lcm(int[] numArray) {
        int lcm = numArray[0];
        for (int i = 1; i < numArray.length; i++) {
            lcm = Lcm(lcm, numArray[i]);
        }
        return lcm;
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值