线性筛法(一)--素数筛法(一)

目录

筛法

所谓筛法是一种思想,就像名字一样,筛去多余的,筛去错误的。多数情况用数组标记,复杂度看起来很大,但代码跑起来确是越跑越快。

素数筛法

问题引入

把n以内素数全找出来(n<=100000)

大家一定想得到第一种方法,暴力,遍历。

//暴力
#include<stdio.h>
#include<math.h>
int isprime(int n)
{
    n = sqrt(n);
    for(int i = 2; i < n; i++)
    {
        if(n%i==0)
            return 0;
    }
    return 1;
}
int main()
{
    scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        if(isprime(n))
            printf("%d ",i);
    }
    return 0;
}

注:用n=sqrt(n),可以增加运算速度,毕竟sqrt也是很慢的。但是这种方法还是很慢,慢在每次都要判断。

接下来看筛法

代码分析

所谓素数,就是不能表示为比它更小的数的乘积。
且,任何一个素数的倍数一定不是素数。

我们先定义一个数组来存100000以内数是否的素数,下标表示数,数组的值1表示是素数,0表示不是素数。

我们可以换个角度思考,要找素数,其实只要把不是素数的排除就可以了。

接下来我们可以构造一张表。
初始
|0|1|2|3|4|5|6|7|8|9|10|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|0|0|0|0|0|0|0|0|0|0|

我们可以把2的倍数变成1,因为任何一个素数的倍数一定不是素数。
|0|1|2|3|4|5|6|7|8|9|10|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|0|1|0|1|0|1|0|1|0|1|

然后是3的倍数
|0|1|2|3|4|5|6|7|8|9|10|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|0|1|0|1|0|1|0|1|1|1|
。。。。。。

照这样就可以得到一张素数表了,哈哈。
看代码。

//筛选法
#include<stdio.h>
#include<math.h>
int a[100001];
int main()
{
    int n;
    while(scanf("%d",&n) == 1)
    {
        for(int i = 2; i <= n; i++)
        {
            if(a[i] == 0)
            {
                for(int j = i*2; j < n; j+=i)
                    a[j] = 1;
            }
        }
        printf("2");
        for(int i = 3; i <= n; i++)
        {
            if(a[i] == 0)
            printf(" %d",i);    
        }
    }
    reutrn 0;
}

这个代码还可以改进。
第一,我们不用筛到n,其实只要和暴力方法一样,筛到sqrt(n)就可以了。
第二,我们筛3时多筛了3*2,筛5时多筛了5*2,5*3,5*4。只要从i*i开始筛就可以了。

//筛选法优化一
#include<stdio.h>
#include<math.h>
int a[100001];
int main()
{
    int n;
    while(scanf("%d",&n) == 1)
    {
        n = sqrt(n);
        for(int i = 2; i <= n; i++)
        {
            if(a[i] == 0)
            {
                for(int j = i*i; j < n; j+=i)
                    a[j] = 1;
            }
        }
        printf("2");
        for(int i = 3; i <= n; i++)
        {
            if(a[i] == 0)
            printf(" %d",i);    
        }
    }
    reutrn 0;
}

其实还可以改进,这里我就不说了。
把2的情况用位运算,再把j+=i变为j+=2*i

总结

看起来时间复杂度为O(n*n),其实在处理很多数据时,它是越跑越快,相当于O(6*n)。

另外

1,如果要判断素数个数,可以用一个数组存一下有几个,结合筛法,也是很方便的。
2,如果要判断50-100有几个素数,只要(100的素数个数-50的素数个数),再判断一下100与50的素数情况。
3,这种筛法叫埃拉托斯特尼筛法。

下一篇:线性筛法(一)--素数筛法(一)

猜你喜欢

转载自www.cnblogs.com/juicebox/p/9644482.html