筛法求素数(普通方法和快速筛)

1.普通的线性筛

原理:素数的倍数是合数,合数的倍数还是合数,把所求区间的合数全都去掉了,剩下的就是素数了

模板:

#include <iostream>
#include <string>
#include <cstdio>
#include <string.h>
#define maxx 20    //maxx是几就表明要求的是 : 从一到几这个范围内的素数

using namespace std;

int su[maxx];//这里面存放的是素数
int book[maxx + 5];//su:素数集合,book[]标记是否为素数,注意一定要加x否则数组溢出特别难查出来
int cnt;//cnt代表的是在su[]这个数组中,因为要往里塞题给范围内的素数嘛,所以这个cnt就是塞素数时的下角标,当然了,还充当输出时的输出上界
void xianxingshai()
{
    cnt=1;
    memset(book,-1,sizeof(book));
    for(int i=2;i<maxx;i++)
    {
        if(book[i]==-1)
        {
            su[cnt++]=i;
        }
        for(int j=i*2;j<maxx;j+=i)
            book[j]=0;
    }
}

int main()
{
    xianxingshai();
    for(int i=1;i<cnt;i++)//因为到最后cnt还是有一个++,故是 i<cnt 而非 i<=cnt
    {
        cout<<su[i]<<" ";
    }
    return 0;
}

2.快速线性筛法

这里有一个大佬的博客https://blog.csdn.net/yangyuhao0408/article/details/50956143(就只看他快速线性筛法那部分就行,和下面这个的代码和思路是一样的,下面这个代码里还有解释)

模板:

#include<iostream>
#include <cstdio>
#include <string.h>
#include <cstring>

using namespace std;

#define maxx 200  //maxx是几就表明要求的是 : 从一到几这个范围内的素数
long long prime[maxx+5];//这个集合中存的是质数的集合
long long num_prime;//num_pirme记录素数个数
int book[maxx];//book[]为-1是素数,为0是合数
void quick_su()
{
    memset(book,-1,sizeof(book));
    num_prime=0;
    book[0]=book[1]=0;
    for(long long i=0;i<=maxx;i++)
    {
        if(book[i]==-1)
        {
            prime[num_prime++]=i;
        }
        for(long long j=0;j<num_prime&&i*prime[j]<=maxx;j++)
        {
            book[i*prime[j]]=0;//是合数故标记为0,同时,prime[j]是合数i*prime[j]的最小素因子
            if( !(i%prime[j]) )//即比一个合数大的质数和该合数的乘积可用一个更大的合数和比其小的质数相乘得到
                break;
        }
    }
}
int main()
{
    quick_su();
    for(int i=0;i<num_prime;i++)//输出
    {
        printf("%lld  ",prime[i]);
    }
        printf("\n");
    return 0;

}

就像:

质数 2可以把4标记成合数    此时 质数集合有 :2

质数 3可以把 6,9 标记成合数    此时 质数集合有 :2,3

质数 5可以把10,15,25标记成合数    此时 质数集合有 :2,3, 5

质数 7可以把 14,21,35,49 标记成合数    此时 质数集合有 :2,3, 5, 7

质数 11可以把 22 , 33 , 55 , 77 , 121 标记成合数    此时 质数集合有 :2,3, 5, 7 ,11

以质数11 标记的合数为例:期中22,33,55,77其实都可以在之前用质数2,3,5,7标记掉

但是,如果之前标记了,现在在标记一遍会重复,所以用    if( !(i%prime[j]) )    break;     的语句来限制用以避免重复。

那么为什么这条语句可以避免重复呢?

因为一个定理:任何一个合数都可以写成几个质数相乘的形式

既然要标记的合数可以被其他更大的质数标记,那么,现在的质数只需要把自己范围内的合数标记了,其他指数范围内需要去标记的合数就没必要标记了:即 break。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值