素数的判断
判断数n是否为一个素数,基本方法为从2开始向后枚举,若n不能被2,3,4,…,n-1整除,则n为素数,该判断方法的时间复杂度为;更快的方法为,当枚举至时即可判断是否为素数,该判断方法的时间复杂度为。
代码如下:
//写法1,其中sqrt函数位于头文件<math.h>,double sqrt(double a)
bool isPrime(int n){
if(n <= 1) return false; //特判
int sqr = (int)sqrt(1.0 * n); //根号n
for(int i = 2; i <= sqr; i++){ //遍历2~根号n
if(n % i == 0) return false;
}
return true;
}
//写法2,当n不接近int型上界时;或i以被定义为long long类型,不至于溢出
bool isPrime(int n){
if(n <= 1) return false;
for(int i = 2; i * i <= n; i++){
if(n % i == 0) return false;
}
return true;
}
!!!注意溢出问题。
素数表的获取
基础方法:1~n枚举
对1~n依次判断是否为素数,其枚举部分复杂度为,判断是否为素数部分为,因此总复杂度为。
当数据量小于时,该算法可行。
代码如下:
cosnt int maxn = 101; //表长
int prime[maxn], pNum = 0; //prime数组存放所有素数,pNum为素数个数
bool p[maxn] = {false}; //p[i] == true表示i为素数
void Find_Prime(){
for(int i = 1; i < maxn; i++){
if(isPrime(i) == true){
prime[pNum++] = i; //把i加入素数表
p[i] == true;
}
}
}
埃氏(Eratosthenes)筛法
对每个素数,划去其所有倍数,剩下的即为素数。时间复杂度为。
当数据量小于时可行,达到附近的难以满足。
举例如下:对2~15进行判断
- 2是素数,筛去2的所有倍数,即4,6,8,10,12,14
剩:2,3,5,7,9,11,13,15 - 3是素数,筛去3的所有倍数,即9,15
剩:2,3,5,7,11,13 - 4已被筛去,非素数
- ……
代码如下:
cosnt int maxn = 101; //表长
int prime[maxn], pNum = 0; //prime数组存放所有素数,pNum为素数个数
bool p[maxn] = {false}; //如果i为素数,则p[i] = false,否则为true
void Find_Prime(){
for(int i = 2; i < maxn; i++){
if(p[i] = false){ //若i为素数
prime[pNum++] = i; //把i加入素数表
for(int j = i + i; j < maxn; j += i) //筛去所有i的倍数
p[i] == true;
}
}
}
注:优化,倍数的筛去从开始,而不是开始,因为在筛查2~的倍数时已经被筛去。
欧拉(线性)筛法
提出背景:由于埃氏筛法在划去倍数的过程中对于一个合数可能进行了多次重复划去,如对于合数30,当划去2,3,5倍数时均对其进行了操作,带来了不必要的重复,进而导致复杂度上升。
主要思想:为避免合数的重复筛查,对每个数,使其被它的最小质因数筛查掉(最小质因数具有唯一性)。
时间复杂度为;当数据量小于时合适。
代码如下:
cosnt int maxn = 101; //表长
int prime[maxn], pNum = 0; //prime数组存放所有素数,pNum为素数个数
bool p[maxn] = {false}; //如果i为素数,则p[i] = false,否则为true
void Find_Prime(){
for(int i = 2; i < maxn; i++){
if(p[i] = false){ //若i为素数
prime[pNum++] = i; //把i加入素数表
}
for(int j = 0; (j < maxn) && (i * prime[j] < maxn); j++){ //筛去基于i的非2最小质因数倍数
p[i * prime[j]] == true; //筛去i * prime[j]
if(i % prime[j] == 0) break; //避免冗余筛查
}
}
}
一些问题:
- 为何该算法遍历了所有1~n?
虽然筛查的内循环部分只遍历了一部分数据,但外循环从1~n进行了遍历并用 if 判断了是否为素数。 - 为何该算法避免了冗余筛查的出现?
因为外循环数不断增加,内循环作为筛查部分每次筛查掉的数为,由于为大于等于2的质数,因此即筛查掉的数均为比大的数。
语句作为终止内循环条件,避免了冗余筛查的作用在于:此时可写为,此时若未终止循环,则下一步将对进行筛查,而此时,又因为显然小于,故必为其最小质因数,因此数必将在未来增加至某个值时被筛查掉,此时。
参考资料
[1]. 《算法笔记》P160-162
[2]. 数论_欧拉筛法
来源:CSDN
作者:Dagger-axe-x
链接:https://blog.csdn.net/m0_46161993/article/details/104171547