挨氏筛和欧拉筛

一、判断素数

素数:除1和他本身外,不能被其他数整除的数;
素数筛: 首先,给你一个区间的正整数,让你求在这段区间内有哪些素数?
这里,我们就可以用“筛选的方法”筛去不是素数的正整数(也就是合数)剩下的就是素数了,但不同的筛法效率也是不一样的。

二、筛选方法

1.暴力求法

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

2.埃氏筛

又称为埃拉托斯特尼筛法,是一种比较古老的筛法,我们直接来看它的筛法原理。其时间复杂度为:
挨氏筛的时间复杂度

1.准备一个判断是否素数的数组,

> bool isPrime[20000];

2.初始化:假设 2 - n都是素数。(1不是,我们先排除)

for(int i=2;i<=n;++i)  
        isPrime[i] = true;  

挨氏筛的完整代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
bool isprime[N];
void Eratosthens(int maxn){
    memset(isprime, true, sizeof(isprime));//注意:memset()函数是对字节赋值
    isprime[0] = isprime[1] = false;
    for(int i = 2; i < maxn; i ++){
        if(isprime[i]){
            for(int j = 2*i; j <=maxn; j = j + i){
                isprime[j] = false;
            }
        }
    }
    return;
}

由于每个数可能有很多除了1和它本身之外的因数,因此在挨氏筛中,每个合数可能重复多次被筛去,要使时间复杂度为线性,我们想要使每个数只被筛去一次。

3.快速线性筛(欧拉筛)

最小质因数:最小质因数是指将一个合数进行分解质因数,把它写成一些质因数相乘的形式,这其中最小的因数就叫做最小质因数。

原理:利用每个数的最小质因子来筛素数。每个数的最小素数因子只有一个,这就使每个合数都只可能被筛去一次。时间复杂度为线性。

i用来控制倍数,红色部分进行break,灰色部分不执行如43=12,4可以分解为22所以用6 * 2 =12 进行筛
快速线性筛
完整代码如下

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
bool isprime[N];
int primes[N], pn;
void FastSieve(int maxn)
{ //筛区间0 ~ maxn之间的素数
    memset(isprime, true, sizeof(isprime));
    isprime[0] = isprime[1] = false;
    pn = 0;
    for (int i = 2; i <= maxn; ++i)
    {
        if (isprime[i])
            primes[pn++] = i;
        for (int j = 0; j < pn && i * primes[j] <= maxn; j++)
        {
            isprime[i * primes[j]] = false;
            if (i % primes[j] == 0)
                break;
        }
    }
    return;
}

例题:

用筛法求之N内的素数。
输入 N
输出 0~N的素数
样例输入 100
样例输出 略

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
bool isprime[N];
int primes[N], pn;
void FastSieve(int maxn)
{ //筛区间0 ~ maxn之间的素数
    memset(isprime, true, sizeof(isprime));
    isprime[0] = isprime[1] = false;
    pn = 0;
    for (int i = 2; i <= maxn; ++i)
    {
        if (isprime[i])
            primes[pn++] = i;
        for (int j = 0; j < pn && i * primes[j] <= maxn; j++) //注意取值范围为≤
        {
            isprime[i * primes[j]] = false;
            if (i % primes[j] == 0)
                break;
        }
    }
    return;
}
int main()
{
    int n;
    cin >> n;
    FastSieve(n);
    for(int i = 0; i < pn; i ++){
         cout << primes[i] << endl;
    }
    // for (int i = 2; i <= n; i++)
    // {
    //     if (isprime[i])
    //         cout << i << endl;
    // }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

释怀°Believe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值