素数筛法程序实现

本文详细介绍了几种常见的质数筛选算法,包括简单的遍历判断、埃拉托斯特尼筛法及改进版本,如忽略偶数的筛法和线性时间筛法。这些算法能有效地找出一定范围内的所有质数,并在ACM竞赛等场景中有着广泛的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    质数是数论中的关键所在,因此很多ACM的题目都需要求出或者判断质数。判断一个数是否为质数很简单。

bool isPrime(int n){
    for(int i=2;i*i<=n;++i)//i*i可能超范围,也可以使用sqrt
        if( 0 == n % i )
            return false;
    return true;
}


    一般而言,相关题目的测试数据都不止一个case,因此比较好的做法是用筛法求出一定范围内所有的质数。
bool isComp[SIZE] = {false};//isComp[i]指示i是否为合数
int P[SIZE] = {0}; //依次保存质数的数组
int PCnt = 0; //质数的个数
void sieve(){
    for(int i=2;i<SIZE;++i){
        if ( isComp[i] ) continue;
        P[PCnt++] = i;
        for(int j=i*i;j<SIZE;j+=i)//i*i同样可能超范围
            isComp[j] = true;
    }
}


    还可以有一个略微快一点的方法,因为偶数显然是合数。
bool isComp[SIZE] = {false};//isComp[i]指示i是否为合数
int P[SIZE] = {2}; //依次保存质数的数组
int PCnt = 1; //质数的个数
void sieve(){
    for(int i=4;i<SIZE;i+=2) isComp[i] = true;
    for(int i=3;i<SIZE;++i){
        if ( isComp[i] ) continue;
        P[PCnt++] = i;
        for(int j=i*i;j<SIZE;j+=i<<1)//i*i同样可能超范围
            isComp[j] = true;
    }
}


    因为没有重复判断偶数,所以上述算法会比原始筛法快一点点。根据“不重复判断”这个原则,有线性时间筛法。如下:
bool isComp[SIZE] = {false};
int P[SIZE] = {0};
int PCnt = 0;
void sieve(){
  for(int i=2;i<SIZE;++i){
    if ( !isComp[i] ) P[PCnt++] = i;
  
    for(int j=0;j<PCnt&&i*P[j]<SIZE;++j){
       isComp[i*P[j]] = true;
       if ( 0 == i % P[j] ) break;
    }
  }
}


    筛法的根本原则是找到一个质数之后,将它的倍数全部标识为合数。而线性筛法则是将所有已知的质数的i倍标识为合数。同时当P[j]是i的最小质因子时,不需要再去标记更大质数的倍数。因为对于更大的质数P[j'],它的i倍可以写作P[j']*i = P[j]*k*P[j'],记住P[j]是i的质因子。所以这个数一定可以在比i更大的i'=P[j']*k的时候找到。因此,比P[j]大的质数在i的时候均不需要考虑。
    例如当已经找到质数2、3、5、7、11、13时,当i为15时,将30、45标识为合数,而75及其以上则不必进行标识。因为当i迭代至25时,75自然会被标识为合数。
    用这种方法确保每一个标志位只被设置一次,因此是线性时间的。同时这种方法可以求出每个整数的最小质因子。
    某些题目中,由于取值范围较大,不可能将范围内的所有质数都筛出来,一般就求得SIZE=sqrt(MAXSIZE)以内的所有质数,保证所有合数的质因子至少已经求出一个。此时判断质数的函数可以如下:
bool isPrime(int x){
    if ( x < SIZE ) return !isComp[x];
    
    for(int i=0;P[i]*P[i]<=x&&i<PCnt;++i)
        if ( 0 == x % P[i] ) 
            return false;
   return true;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值