素数筛

素数又称质数,素数指除了1和他本身,不能被任何数整除的数,素数>=2,非素数叫做合数,比如16是合数,19是素数

学会了素数的几种筛法,你就可以像普奇神父一样随时让自己冷静下来(说不定想不起来有哪些质数而更加暴躁)

最最普通的做法:

一 .枚举

判断一个数n是否为素数,只需要用2~n-1的每一个数去除,若能被整除则不是素数:

int isPrime(int n){
    if(n<=1)
    return 0;
    
        for(int i = 2;i<n;i++){
            if(n%i==0)
            return 0;    //0代表不是素数 
        }
        return 1; //1代表是素数 

}

稍微优化:

若n可以被2~n-1的整数整除,其两个因子必然有一个大于等于√ n ,一个小于等于√ n

则有:

int isPrime(int n){
    if(n<=1)
    return 0;
    
        for(int i = 2;i*i<=n;i++){
            if(n%i==0)
            return 0;    //0代表不是素数 
        }
        return 1; //1代表是素数 

}

 

二. 埃氏筛(埃拉特斯特尼筛法)

素数的倍数都是合数,用一个数组来标记素数和合数,筛去所有的合数

比如:2的倍数:4,6,8,10

      3的倍数:6,9,15,18

void isPrime(int n){//求0-n之间的素数 
    memset(prime,0,sizeof(prime));//用0表示素数 
    for(int i = 2;i*i<n;i++){
        if(prime[i]==0){
            for(int j = 2*i;j<=n;j+=i){      //这里的j+=i就相当于j是i的倍数:例如:4,6,8,10.每次加2,j每次加3i-2i=i;
                prime[j] = 1;
            } 
        }
    }    
}

 

进一步优化:

看一看i = 5时,我们在第二层循环里筛去2*5,3*5,4*5,5*5等等,在i = 2,3,4时,已经有过5*2,5*3,5*4,所以我们第二层循环的起点设为i*i即可

void isPrime(int n){//求0-n之间的素数 
    memset(prime,0,sizeof(prime));//用0表示素数 
    for(int i = 2;i*i<n;i++){
        if(prime[i]==0){
            for(int j = i*i;j<=n;j+=i){
                prime[j] = 1;
            } 
        }
    }    
}

这样的埃氏筛仍然有重复判断:

 

我们来看一个效率更高的方法:

三.欧拉筛

一个合数可以分解为多个素数的乘积(简单的想一想:每个合数都有因数,因数中的非素数还可以继续分解,直到最后只剩下素数)

如:12 = 2*2*3

先写到这里,改日再来

posted @ 2020-03-21 22:21  ziggystardust  阅读(200)  评论(0)    收藏  举报