关于埃氏筛法详解

版权声明:原创文章如需转载请注明出处 https://blog.csdn.net/holly_Z_P_F/article/details/85063174

那天的ppt讲的不是很清楚  下来后好多同学都说没听懂(。。。。。)

我再补充一下

首先  关于原理

ppt上讲的很清楚了  这个原理是相对简单的  很好理解

如果原理你都理解了 那么你直接去后边看用法

如果 你还没有理解  那么  我再举个例子

最朴素的判断素数方法 是这样的 对吧

那么 现在我让你判断1-20 之内的素数   你会怎么做

从1 遍历到20   挨个判断一下是不是素数 对吧 

那么我们来分析一下复杂度  如果不理解什么是复杂度  你就认为我们算一下循环次数好了

从1-20 需要遍历20次  对于每个数 极端情况下 需要sqrt(n)次才完成能判断

这一共是多少次呢  sqrt(2)+sqrt(3)+sqrt(4)+sqrt(5)+.........sqrt(20) 次 对吗 

通过计算器  计算得到 答案是60   也就是需要60次

那么我们再来看下 我们使用埃氏筛需要几次

首先 外面的循环  毋庸置疑 从2-20遍历  需要20次(其实是19  我们忽略 进为20)

我们来看里面的操作

从2开始 2是素数  那么4不是 6不是  8也不是 10、12、14、16、18、20 都不是  这是9次操作

然后3开始 6 9 12 15 18 都不是素数  这是5次操作

然后4 跳过 5 跳过 6 跳过  

从7开始 14  不是素数  这是1次操作 

后边的 8 9 10 11 12  14 15 16 18 20  都会跳过  

而11 13 17 19 都不会操作   因为他们的倍数 大于20了

那么一共进行了20+9+5+1=35次操作   比那个60少了将近一半

其实因为我举的例子很小  只到20  所以你看到的才快了这么点

你可以想一下  如果数字变得很大的时候  比如一千万 你用普通的筛法 是需要更多次数的

所以 这个埃氏筛法快的其实不止这么一点--(至于究竟快多少 先不管了 你只要知道很快就好了)

下面说下   怎么用它

明白了 原理  用起来就很灵活了

比如

问题一     求1-20之间的素数个数

int main(){
    int cnt=0;//用来计数
    
    bool isprime[21];
    for(int i=0;i<=20;i++)isprime[i]=true;//先全部置为真

    isprime[0]=isprime[1]=false;//1 0 不是素数

    for(int i=2;i<=20;i++){//从2开始往后筛
        if(isprime[i]){
            for(int j=2*i;j<=20;j+=i){
                isprime[j]=false;
            }
        }
        if(isprime[i]){
            cnt++;//如果是素数 就计数
        }
    }
    printf("%d",cnt);
}

问题二

就是ppt上的题目

#include<stdio.h>
#include<algorithm>
#include<math.h>
const int maxn=1e6+7;//总的范围规定在这里
using namespace std;

//我们将这个埃氏筛法写成一个函数
bool isprime[maxn];
void sieve(){
    for(int i=0;i<=maxn;i++)isprime[i]=true;
    isprime[0]=isprime[1]=false;
    for(int i=2;i<=maxn;i++){//从2开始往后筛
        if(isprime[i]){
            for(int j=2*i;j<=maxn;j+=i){
                isprime[j]=false;
            }
        }
    }
}

int l,r; 
int main(){
    //我们在程序刚开始 先调用这个函数
    //把这个isprime数组处理成我们想要的样子 用来判断素数
    //这就是预处理的思想 我们在开头处理这一次
    //把isprime数组 里面 下标是素数的全部变成了true
    //后边想判断是不是素数 直接用isprime[i]是不是真就好了
    sieve();
    
    
    int cnt=0;//计数
    scanf("%d%d",&l&r);//输入 l和r
    for(int i=l;i<=r;i++){//遍历 l到r  判断就行了
        if(isprime[i]){
            cnt++;
        }
    }
    printf("%d",cnt);
}

问题三 输入一个数n   判断他是不是素数(多组测试数据)

n的范围是 (n<1e6)

这个题很有意思  题上说有多组测试数据(没说几组)  每次给你一个n

那么其实意思就是说 有很多个n让你判断 他们是不是素数

而且n最大是1e6

那么你们想一下

如果我第一个数给你1000000   你用普通的判断素数的方法  需要sqrt(n)次才能判断出来

也就是3000次才能判断出来是不是素数  对吧

3000次也不多  那如果我输入一共一万组呢   就需要3000*10000次了吧

所以 这个时候 就体现了 预处理的重要性

我们先预处理出来 1e6以内的所有素数  这样不管你输入啥  我直接去看 是不是素数就好了

对吧

那么 预处理 有些同学也想到了 但是他用最普通的筛法去做预处理

那么你想一下 1e6每个你都需要去判断一下是不是素数  我刚才在上边算了 20以内的素数需要60次才能判断出来

那1e6以内  需要多少次呢  我告诉你 大概需要1e9次(也就是十亿次)

而用埃氏筛法需要几次呢  可能你们现在还不会算 我直接告诉你们 需要70万次

十亿 和 七十万  差别不用我说了吧    这就是这个算法的效率  也是算法的魅力所在。

#include<stdio.h>
#include<algorithm>
#include<math.h>
const int maxn=1e6+7;//总的范围规定在这里
using namespace std;

//我们将这个埃氏筛法写成一个函数
bool isprime[maxn];
void sieve(){
    for(int i=0;i<=maxn;i++)isprime[i]=true;
    isprime[0]=isprime[1]=false;
    for(int i=2;i<=maxn;i++){//从2开始往后筛
        if(isprime[i]){
            for(int j=2*i;j<=maxn;j+=i){
                isprime[j]=false;
            }
        }
    }
}

int n; 
int main(){
    sieve();//预处理
    
    //输入 n
    while(scanf("%d",&n)!=EOF){
        if(isprime[n]){
            printf("Yes\n");
        }
        else{
            printf("No\n");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/holly_Z_P_F/article/details/85063174
今日推荐