筛法求素数

1. 朴素筛法

直接一个个去试

bool is_prime( int m )
{

    for ( int i = 2; i < m; ++i ) {
        if ( m % i == 0)
                return false;
    }

    return true;
}

可以排除所有除2以外的偶数, 对剩下的奇数进行判断。


bool is_prime( int m )
{
    if ( m == 1)
        return false;
    if ( m == 2)
        return true;
    if ( m % 2 == 0 )
        return false;

        for ( int i = 3; i < m; i += 2 )
                if ( m % i == 0)
                        return false;

    return true;
}

素数肯定是成对出现的,因此我们可以判断到sqrt(m)

  • 定理一
    ∀ 合数 a ,即可以表示为 a = b c   , 1 < b ≤ c < a ; 则必有 b ≤ a , c ≥ a . 因若不然则有 b c > a ,矛盾。 \forall 合数a,即可以表示为 a = b c\ ,1 < b \le c < a;\\ 则必有b\le \sqrt{a},c \ge \sqrt{a}.\\因若不然则有bc > a,矛盾。 合数a,即可以表示为a=bc ,1<bc<a;则必有ba ,ca .因若不然则有bc>a,矛盾。
bool is_prime( int m )
{
    if ( m == 1)
        return false;
    if ( m == 2)
        return true;
    if ( m % 2 == 0 )
        return false;

        for ( int i = 3; i <= m / i; i += 2 )
                if ( m % i == 0)
                        return false;

    return true;
}

2. 埃氏筛法

对于普通筛法我们需要判断sqrt( m ) - 1个数,然而我们可以通过记录 1 ~ sqrt(m)内的质数的方式来减少不必要的合数判断。

  • 推论1

∀ 合数 a , 必有质因数 p ≤ a 证明 : 设 b 为 a 在 a 以内的因子; 若 b 是素数,则推论成立; 若 b 为合数,根据算数基本定理, b 必有素因子,则 b 的质因数也为 a 的质因数 ; 推论一成立 \forall 合数a, 必有质因数p \le \sqrt{a}\\ 证明: 设b为a在\sqrt{a}以内的因子;\\若b是素数,则推论成立;\\若b为合数,根据算数基本定理,b必有素因子,则b的质因数也为a的质因数;\\ 推论一成立 合数a,必有质因数pa 证明:baa 以内的因子;b是素数,则推论成立;b为合数,根据算数基本定理,b必有素因子,则b的质因数也为a的质因数;推论一成立
也就是说通过求出1 ~ 10的质数,我们可以筛去11 ~ 100中的合数,进而剩下的都是质数,

再将其添加到质数表中。

int prime_cnt = 0;
int not_prime[10000 + 1] = {0};
int prime_table[1000] = {};

void era_prime( int maxNum ) {


    for ( int i = 2; i <= maxNum; ++i ) {
        if ( !not_prime[i]) {
                for ( int j = i * i; j <= maxNum; j += i) {
                        not_prime[j] = 1;
                }
                 prime_table[ prime_cnt++] = i;
        }

    }
}


3. 欧拉筛

  • 算数基本定理

∀ a > 1 , a = p 1 r 1 p 2 r 2 . . . p n r n , p i 为质数 , r i 为系数,且分解形式唯一。 \forall a > 1, a = p_1^{r_1}p_2^{r_2}...p_n^{r_n}, p_i 为质数, r_i为系数,且分解形式唯一。 a>1,a=p1r1p2r2...pnrn,pi为质数,ri为系数,且分解形式唯一。

每个数都只能从最小的质因数所筛去

void eular_prime( int maxNum ) {

   for ( int i = 2; i <= maxNum; ++i) {
       if (!not_prime[i])
               prime_table[prime_cnt++] = i;
       for ( int j = 0; j <  prime_cnt && i  <= maxNum/ prime_table[j]; ++j) {
           not_prime[ i * prime_table[j] ] = 1;
           if ( i % prime_table[j] == 0)
                   break;
       }
   }

}



你可能感兴趣的:(算法,数据结构,c++)