引子
个人比较喜欢算法,在日常解题过程中,经常遇到各种跟素数有关的问题。为了方便未来使用,总结创建了素数工具类。
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;
}
}