一、试除法O()
1、判定质数
主要思想:通过遍历除数看是否能够除尽。由于除数总是成对出现(例:6的除数是2和3),只要遍历到即可。虽然由可以推出,但判断条件里写每次都要计算一遍,增加时间开销;判断条件里写i*i=n当n比较大的时候i*i的结果可能存在溢出,影响条件判断。故在实际编程中的最优判断条件为i=n/i。
bool is_prim(int n){
if(n<=2) return true;
for(int i=2;i<=n/i;i++){//注意循环判断条件
if(n%i==0) return false;
}
return true;
}
2、分解质因子
主要思想:若n中存在两个大于的因子,则它们的乘积必定大于n,产生矛盾,故n中至多只有一个大于的因子,只要单独处理这种情况,我们就可以只循环n/i次,大大降低了计算时间。循环到第i次时,n已经不包含小于i的因子,故当n%i==0时,i也不包含小于i的因子,因此i必定是质数。
void divide(int n){
for(int i=2;i<=n/i;i++){//减少循环次数降低计算时间
if(n%i==0){//找到n的因子,i必定是质数
int s=0;
while(n%i==0){
n/=i;//去掉n中所有小于i的因子
s++;
}
printf("%d %d\n",i,s);
}
}
if(n>1) printf("%d %d\n",n,1);//最后剩下的是那个大于根号n的质因子
puts("");
}
二、筛数法
1、埃氏筛数法O(nlog(logn))
主要思想:从2开始遍历到n,将每次遍历数i的倍数都筛掉,最终剩下的全是质数。埃氏筛数法只需要筛掉质数的倍数,降低了计算时间。
void get_primes_A(int n){
int cnt=0;
for(int i=2;i<=n;i++){
if(!st[i]){
primes[cnt++]=i;//i是质数,加入集合
for(int j=i+i;j<=n;j+i) st[j]=true;//筛掉i的倍数
}
}
}
2、线性筛数法O(n)
主要思想:每个数都用它的最小质因子来筛除,确保了不会出现重复筛除的情况,将计算时间降低到线性。当i%primes[j]==0成立时,由于j是递增遍历,primes[j]一定是i的最小质因子,故也一定是primes[j]*i的最小质因子,后面的数再参与筛除将会造成重复筛的情况,跳出循环。
void get_primes_X(int n){
int cnt=0;
for(int i=2;i<=n;i++){
if(!st[i]) primes[cnt++]=i;
for(int j=0;primes[j]<=n/i;j++){//注意循环判定条件
st[primes[j]*i]=true;//由质数倒推它做最小质因子对应的数,筛掉
if(i%primes[j]==0) break;//已经到此次筛除的最大限度,避免重复筛
}
}
}