欧拉筛(求质数)

Posted laplus

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了欧拉筛(求质数)相关的知识,希望对你有一定的参考价值。

先上代码:

技术分享图片
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<time.h>
using namespace std;
int prime[10000001];//存素数 
bool vis[10000001];//保证不做素数的倍数 
int main()
{
    int n, cnt = 0;
    scanf("%d", &n);
    clock_t start = clock();
    memset(vis, false, sizeof(vis));//初始化 
    memset(prime, 0, sizeof(prime));
    for(int i = 2; i <= n; i++)
    {
        if(!vis[i])
        {
            prime[cnt++] = i;
            for(int j=1;j*i<=n;j++)
            {
                vis[j*i]=true;
            }
        }
    }
    clock_t ends = clock();
    cout <<"Running Time : "<<(double)(ends - start)/ CLOCKS_PER_SEC << endl;
    printf("%d\n", cnt);
    return 0;
}
View Code

这并不是完整的欧拉筛,上面的代码从2开始把素数的倍数全部标记为非质数,计算一千万以内的质数个数只需要0.23s

完整欧拉筛代码:

技术分享图片
#include<stdio.h>
#include<string.h>
#include<time.h>
#include<iostream>
using namespace std;
int prime[10000001];
bool vis[10000001];
int main()
{
    int n, cnt = 0;
    scanf("%d", &n);
    clock_t start = clock();
    memset(vis, false, sizeof(vis));
    memset(prime, 0, sizeof(prime));
    for(int i = 2; i <= n; i++)
    {
        if(!vis[i])
        prime[cnt++] = i;
        for(int j = 0; j<cnt && i*prime[j]<=n; j++)
        {
            vis[i*prime[j]] = true;
            if(i % prime[j] == 0) break;
        }
    }
    clock_t ends = clock();
    cout <<"Running Time : "<<(double)(ends - start)/ CLOCKS_PER_SEC << endl;
    printf("%d\n", cnt);
    return 0;
}
View Code

计算一千万以内的质数个数只需要0.12s

先讲讲为什么可以这样算质数吧

首先,先将所有的数标记为质数,然后从2开始,因为2是质数所以它的倍数肯定不是质数,然后3同理,4已经被标记为非质数了跳过,5质数,6也被标记为非质数了跳过.....

然后讲一讲为什么第一个会比第二个快

为什么会这样了?

首先,第一个代码标记2的倍数是标记过1次6,而标记3的倍数时有标记了一次6,所以重复标记花费了时间

而第二个代码,因为这句代码而没有进行重复标记:

for(int j = 0; j<cnt && i*prime[j]<=n; j++)
{
  vis[i*prime[j]] = true;
  if(i % prime[j] == 0) break;//重点
}

当 i % prime[j] == 0,相当于i=k*prime[j],所以i*preime[i+1]=k*prime[j]*preime[i+1],是质数的倍数,而后面会对他进行标记,所以这次就跳过,终止循环.

第一个代码也可以这样写:

技术分享图片
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<time.h>
using namespace std;
int prime[10000001];//存素数 
bool vis[10000001];//保证不做素数的倍数 
int main()
{
    int n, cnt = 0;
    scanf("%d", &n);
    clock_t start = clock();
    memset(vis, false, sizeof(vis));//初始化 
    memset(prime, 0, sizeof(prime));
    for(int i = 2; i <= n; i++)
    {
        if(!vis[i])
        {
            prime[cnt++] = i;
        }
        for(int j = 0; j<cnt && i*prime[j]<=n; j++)
        {
            vis[i*prime[j]] = true;
        }
    }
    clock_t ends = clock();
    cout <<"Running Time : "<<(double)(ends - start)/ CLOCKS_PER_SEC << endl;
    printf("%d\n", cnt);
    return 0;
}
View Code

 





以上是关于欧拉筛(求质数)的主要内容,如果未能解决你的问题,请参考以下文章

线性筛法求质数

9/4 经典dp+线性筛求质数+混合背包

素数筛法

蓝桥杯中常用的数学算法

蓝桥杯中常用的数学算法

欧拉筛(线性筛)