素数筛的总结与记录

目录:(1,2判断一个属是否为素数数据范围较小,3,4可用于大数据,4,5可用于求区间素数个数)

  1. 素数定义法
  2. 六倍判定法
  3. 埃氏筛
  4. 欧拉筛
  5. 区间筛
  6. Miller-Rabin算法

第一款:素数定义判断法
复杂度n^(1/2)

int prime1(long long x)//暴力法
{
    long long i;
    int flag=1;
    if(flag==1)return 0;//特判1不是素数
    for(int i=2;i<=sqrt(x);i++)//遍历1到x^1/2的每个数 找到可能的因子
    {
        if(x%i==0)
        {
            flag=0;
            break;
        }    
    }
    return flag;
 } 

第二款:六倍法判断素数

int prime2(int n)//六倍判断法
{

    if (n==2||n==3){
        return 1;
    }
    if (n%6!=1&&n%6!=5){
        return 0;
    }
    for (int i=5;i<=sqrt(n);i+=6){
        if (n%i==0||n%(i+2)==0){
            return 0;
        }
    }
    return 1;
}

第三款:埃氏筛

//求区间里的所有素数 
const int maxn = 1e4;
bool number[maxn+10];
void prime3() {
    int i, j;
    memset(number, true, sizeof(number));//将所有数标记为素数 
        number[0]=false;number[1]=false;
    for (i = 2; i <= maxn; i++) {
        if (number[i] == true) {
            for (j = i*i; j <= maxn; j+=i)
                number[j] = false;//将合数筛选出来 
        }
    }
}

第四款:欧拉筛

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;//数组的大小
const int N=1e5;//最大的质数的大小
bool vis[maxn];
int prime[maxn],cnt;

void init()
{
    memset(vis,false, sizeof(vis));//所有数初始化为0->质数
    vis[0]=true;
    vis[1]=true;
    cnt=0;
}

void Is_Prime()
{
    init();
    for(int i=2;i<=N;i++)
    {
        if(!vis[i])//i是质数
            prime[++cnt]=i;//prime是用来存质数的数组,显然数组中的质数是从小到大
        for(int j=1;j<=cnt;j++)
        {
            if(i*prime[j]>N)//超出了范围
                break;
            vis[i*prime[j]]=true;
            if(i % prime[j] == 0)//跑到了i的最小的质因数
                break;
        }
    }
}

第五款:区间筛

//区间筛 用于求区间a,b中间素数的个数 
bool v1[Max_n1]; //数组大小为sqrt(b)
bool v2[Max_n2]; //数组大小为b-a
#define long long ll 
ll Prime(ll a,ll b){
    for(ll i=0;i*i<b;i++)v1[i]=true;
    for(ll i=0;i<b-a;i++)v2[i]=true;

    for(ll i=2;i*i<b;i++){
        if(v1[i]){
            for(ll j=2*i;j*j<b;j+=i)v1[j]=false; //筛[2,b)
            for(ll j=max(2LL,(a+i-1)/i)*i;j<b;j+=i)v2[j-a]=false; //筛[a,b)
            //2LL是2的长整数形式
            //((a+i-1)/i)*i是符合>=a最小是i倍数的数
        }
    }
    ll k=0;
    for(ll i=0;i<b-a;i++){
        if(v2[i])k++;
    }
    return k;
}

6.Miller-Rabin算法快速判断大数是否为素数
(数学解释没理解 只会用板子)

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll qul_mul(ll a, ll b, ll n)  //快速积运算,快速求出a^m^*a^m^并且能防止爆掉
{
    ll num = 0;
     while (b)
    {
        if (b&1)
        {
            num=(num+a)%n;    
        }      
        a = (a+a)%n;
        b>>=1;
    } 
    return num;
}
ll qul_pow(ll a, ll b, ll n) //快速幂计算快速求出a^m^的值
{
    ll sum = 1;
    while (b)
    {
          if (b&1)
          {
              sum = sum * a % n;
          }          
          a=a*a%n;
          b>>=1;
    }

     return sum;
}

bool Miller_Rabin(ll n)
{
    int m = n-1;
    int t = 0;
    if (n==2)
    {
         return true;
    }
    else if (n<2 || !(n&1))
    {
         return false;
    } 
     //求出n-1 = m*2^t的m和t。
    while (!(m&1))
    {
        m>>=1;
        t++;
    }
    for (int i=0; i<20; i++)
    {    
        //随机数a
        ll a = rand()%(n-1) + 1;
        // 计算a^m
        ll x = qul_pow(a, m, n), y;          
        for (int j=0; j<t; j++)
        {
            y = qul_mul(x, x, n);  //进行(x*x)%n操作。              
               //不满足二次探测定理,也就是y得1了但是x并不等于1或者n-1,那么n就一定不是质数。
            if (y==1 && x!=1 && x!=n-1)
            {
                 return false;
            }  
            x = y;
        }
          //上面循环跑完了,如果最后x都不等于1,那么一定是一个合数了。
        if (x!=1)
        {
            return false;
        }
    }
    return true;
}

int main()
{
    ll n;
    while (cin >> n)
    {
        if( Miller_Rabin(n)==true)
        cout <<"yes"<<endl;
        else cout<<"no"<<endl;
    }
    return 0;
}

参考文章:
1.素数筛详解
2.素数_埃氏筛法&&线性筛(欧拉筛法)【详解】
埃氏筛法、区间筛法(求素数个数)
Miller-Rabin算法

全部评论

相关推荐

11-15 19:28
已编辑
蚌埠坦克学院 硬件开发
点赞 评论 收藏
分享
Hello_WordN:咱就是说,除了生命其他都是小事,希望面试官平安,希望各位平时也多注意安全
点赞 评论 收藏
分享
评论
1
1
分享
牛客网
牛客企业服务