今天在做pat的算法题时,遇到一道算法:写出一定范围内的素数想了半天没有思路,后来用的方法也是错的,只能上网搜索文章最后总结了相关的算法
当问题是一定范围内的素数时
遇到这种问题一般有两种解法,我会直接给大家提供优化过的算法
算法一:
算法如下:
public static void prime1(int nMax){
//arr数组是一个标记数组其长度为 :范围最大值 + 1;
int[] arr = new int[nMax + 1];
//该数组是存储运算结果。
int[] res = new int[nMax / 2];
res[0] = 1;
res[1] = 2;
//这里的k从2开始。
int k = 2;
for(int i = 3;i <= nMax;i += 2){
arr[i + 1] = 1;
if(arr[i] == 0){
res[k++] = i;
for(int j = i;j * i <= nMax;j++){
arr[i * j] = 1;
}
}
}
}
算法二:
算法如下:
public static void prime2(int nMax){
//arr数组是一个标记数组其长度为 :范围最大值 + 1;
int[] arr = new int[nMax + 1];
//该数组是存储运算结果。
int[] res = new int[nMax / 2];
//标记所有偶数并排除2;
arr[0] = 1;
for(int i = 4;i <= nMax;i += 2){
arr[i] = 1;
}
//从sqrt对重复标记进行优化,从只对奇数进行判断做重复标记优化。从j的起始值设置为i减少重复标记
for(int i = 3;i <= Math.sqrt(nMax);i += 2){
arr[i + 1] = 1;
if(arr[i] == 0){
for(int j = i;j * i <= nMax;j++){
arr[j * i] = 1;
}
}
}
int k = 0;
for(int i = 0;i < arr.length;i++){
if(arr[i] == 0){
res[k++] = i;
}
}
}
两种算法的比较:
这个程序后面补了一个循环,和之前的程序相比,效率似乎反而降低了。之前的程序,在一遍循环中完成标记和存储两个任务,而这个程序需要三个循环。但由于该循环使用的条件是开方所以该程序在数据量极大的情况下可能可以有效减少运行时间。
注意:java的数组不能长度超过2^32 - 1
当问题是判断单个数是否为素数;
遇到这种情况直接使用如下算法:
public static boolean primeSingle(int arg){
if(arg == 1 || arg == 2)return true;
if(arg % 2 == 0)return false;
for(int i = 3; i <= Math.sqrt(arg);i += 2){
if(arg % i == 0)return false;
}
return true;
}
这些代码看起来都很简单,但其都是经过多次优化的代码,所以要了解其原理最好找一篇相关文章看看,我推荐这篇文章:
本文介绍了两种求一定范围内素数的Java算法,包括一个标记数组法和一个优化后的重复标记法。还提到针对单个数的素性判断算法。推荐阅读关于素数筛的详细总结文章以深入了解原理。
2870

被折叠的 条评论
为什么被折叠?



