质数

1.质数的判定:

判断一个数n是否为质数,可以用试除法,枚举2到sqrt(n)即可。

bool is_prime(int n)
{
    if(n==1)
        return false;
    for(int i=2;i<=sqrt(n);i++)
    {
        if(n%i==0)
            return false;
    }
    return true;
}

2.质数的筛选

给定一个整数n,求出1到n之间的所有质数,称为质数的筛选问题。

Eratosthenes筛法:任意整数x的倍数都不是质数。

所以我们可以从2开始依次扫描每个数x,把x的倍数都标记为合数,当扫描到一个没有被标记的数时,那该数为质数。

void primes(int n)
{
    memset(v,0,sizeof(v));
    for(int i=2;i<=n;i++)
    {
        if(v[i])
            continue;
        cout<<i<<endl;//i是质数
        for(int j=i+i;j<=n;j+=i)
            c[j]=1;
    }
}

这样会发现会重复把一个数标记为合数,仔细想想会发现小于x2的x的倍数在扫描更小的时候就被标记过了,

所以可以对Eratosthenes进行优化,对于每个数x,只需要从x2开始遍历就可以了。

void primes(int n)
{
    memset(v,0,sizeof(v));
    for(int i=2;i<=n;i++)
    {
        if(v[i])
            continue;
        cout<<i<<endl;
        for(int j=i;j<=n/i;j++)
            c[i*j]=1;
    }
}

线性筛法:

优化后的Eratosthenes筛法依然会重复标记合数,比如12会被2和3标记,主要的原因是没有唯一确定产生12的方式。

线性筛法是通过从大到小累积质因子的方式标记每个合数,即让12只有3*2*2这一种方式产生。

是数组v记录每个数的最小质因子,按照以下步骤维护v即可。

1:依次考虑2到n之间的每一个数i。

2:如果v[i]=i,说明i是质数,把他保存下来.

3:扫描不大于v[i]的每个质数p,v[i*p]=p。就是在i的基础上累积一个质因子p。

int v[MAX_N],prime[MAX_N];
void primes(int n)
{
    memset(v,0,sizeof(v));
    m=0;//质数的数量
    for(int i=2;i<=n;i++)
    {
        if(v[i]==0)//i是质数
        {
            v[i]=i;
            prime[++m]=i;
        }
        for(int j=1;j<=m;j++)//给当前的数i乘上一个质因子
        {
            if(prime[j]>v[i]||prime[j]>n/i)
                break;
            v[i*prime[j]]=prime[j];
        }
    }
    for(int i=1;i<=m;i++)
        cout<<prime[i]<<endl;
}

 3:质因子分解

任何一个大于1的正整数都能唯一分解为有限个质数的乘积。

将n进行质因子分解可以先用Eratosthenes筛法求出1到n里的素数存入a[i],任何枚举遍历素数即可。

posted @ 2020-03-20 17:10  ~zcb  阅读(196)  评论(0编辑  收藏  举报