素数判定的三种方法(cpp代码)

假如想象 提交于 2020-02-13 12:15:23


一般方法

原理概述:
1不是质数也不是合数,特殊处理;
从2枚举到 √x,若有能除尽的数直接返回x不是素数
Q:为什么枚举到√x?

若m整除n(其中n>根号m)则m=n*k。 若m不整除从1除到√m的数它就不可能整除根号m后面的数。
如果根号m有小于√m的因子X,那么N必定有大于√m的因子Y与X对应。 而且X *Y=m
(来源:百度)

实现说明:

bool isPrime_usual(int x)
{
    if(x==1)
        return false;
    for(int i=2; i*i<=x; i++)
        if(x%i==0)
            return false;
    return true;
}

埃拉托斯特尼筛法(埃氏筛)

原理概述:
从最小的素数2开始,2…3…5…将这些数的倍数标为合数。
实现说明:
首先要有一个数组vis,用来标记那些数是素数,所得结果也存在这个数组,并都初始化为true(即默认所有数都是素数)
从2开始枚举,若vis[i]==true,则用一个循环去将vis[i]的倍数都标记为非素数。个人感受j从i * i开始好一些,有一些从j=2*i开始会降低效率(重复筛)。

bool vis[Maxn];
void isPrinme_era()
{
    memset(vis,true,sizeof(vis));
    for(int i=2; i<maxn; i++)
    {
        if(vis)
            for(int j=i*i; j<Maxn; j+=i)
                vis[j]=false;
    }
}

线性筛

原理概述:
在普通筛的基础上,筛数时只用该合数最小的因子筛掉这个数。
实现说明:
首先需要两个数组p和vis,p用来存素数,vis用来标记素数。
从2开始,将i录入数组p,与埃氏筛一样,再用一个循环去将i的倍数标记为非素数,不同点在于,每一个j循环标记只标记一部分,剩下的让后面的i去标记,这样就避免了重复标记。
举个例子,当i=6时,cnt=3,p数组中存有2 3 5.此时,标记完vis[26=12]=false即退出j循环不去标记vis[36=18]-flase,等i=9时,vis[2*9=18]=false去标记,
至于为什么判断条件是i%p[j]==0,若满足条件的话,i必能拆成i=p[j]*k的形式,这就说明后面必然有更大的i与p[j]相乘能得当前的i *p[j+1].
比如,6=2 *3,而当前3 *6=18 说明18必含因子2然后2 *i=18,这个i绝对大于6.

bool vis[Maxn];
void isPrime_linear()
{
    int cnt=0;
    int p[Maxn];
    memset(vis,true,sizeof(vis));
    for(int i=2; i<=Maxn; i++)
    {
        if(vis)
            p[cnt++]=i;
        for(int j=0; j<cne&&i*p[j]<maxn; j++)
        {
            vis[i*p[j]=false;
                if(i%p[j]==0)
                break;
        }
    }

}

小结: 单比效率线性筛是最快的时间复杂度无限接近O(n),第一种方法较方便,代码量少,但每次只能进行单个数的判断。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!