突发奇想,把自己写的算法程序都总结下,方便日后翻看,也希望能与大家交流、改善算法的速度和简洁性。
算法的核心我都会写在代码的注释中,总体思路简单的我就不写了,有趣或复杂的我当然会写出来啦。
1. 计算得出一亿内的素数
知识清单: 素数-维基百科
package common;
// import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* ComputePrime
*/
public class ComputePrime {
public static void main(String[] args) {
int maxnum = 10000 * 10000; //一亿
long start = System.currentTimeMillis();
List<Integer> primes = getPrimes(maxnum);
long end = System.currentTimeMillis();
System.out.println(String.format("计算 %d 以内的素数, 总计: %d 个, 耗费时间: %d ms", maxnum, primes.size(), end-start));
// 👇 赶紧注释了,当 maxnum = 一亿时,容易爆炸
// primes.forEach(n -> System.out.print(n + ", "));
}
/**
* 得到某个范围内的素数集合
* @param maxnum
* @return
*/
public static List<Integer> getPrimes(int maxnum){
//因为不知道maxnum的大小,用ArrayList不好初始化大小,故而用LinkedList
List<Integer> primes = new LinkedList<>();
primes.add(2);
for(int i=2; i<maxnum; i++){
if(isPrime(i, primes)) primes.add(i);
}
return primes;
}
//传入 n 和 n 前面的数据集合,来判断 n 是不是素数
private static boolean isPrime(int n, List<Integer> primes){
int n_sqrt = (int) Math.sqrt(n);
for(int p : primes){
if(p > n_sqrt) break; //这行代码就是单车和飞机的区别,不信你注释了跑个一百万试试
if(n % p == 0) return false;
}
return true;
}
}
测试找出 100,000,000 / 一亿 内的所有素数,用时 30 秒,可以接受,结果如下图:
第二天更新:采用新的算法,速度达到 2 秒以内!
/**
* 埃拉托斯特尼筛法
* @param n
*/
public static List<Integer> eratosthenes(int n) {
BitSet primes = new BitSet(n);
for(int i=2, len=n+1; i<len; i++) { //初始化所有位图为true
primes.set(i);
}
//帅选n以内所有的质数
for(int i=2, end=(int) Math.sqrt(n)+1; i<end; i++) {
if(primes.get(i)) {
for(int j=i*i,len=n+1; j<len; j+=i){
primes.clear(j);
}
}
}
List<Integer> primesList = new ArrayList<>(primes.cardinality());
for(int i=2, len=n+1; i<len; i++) {
if(primes.get(i)) primesList.add(i);
}
return primesList;
}