质数

本文详细介绍了质数判定的试除法,包括时间复杂度为O(N)和O(sqrt(N))的两种实现,并分析了优化原因。同时,讲解了分解质因数的方法,同样给出了两种时间复杂度的实现。最后,讨论了朴素筛法和埃氏筛法在求解质数个数及数值上的应用,分析了它们的时间复杂度并对比了不同筛法的效率。
摘要由CSDN通过智能技术生成

质数:在大于1的正整数中,如果只有1和本身两个约数,就是质数。或者叫素数。

(1)判定素数——试除法

1.1 时间复杂度O(N)

bool is_prime(int n)
{
    if(n<2)return false ;
    for(int i=2;i<n;i++)
       if(n%i==0)return false;
       return true;
}

数据范围2^31==2^10,运行超时会。

这里是i<n;

1.2时间复杂度O(sqrt(N))

知识点:

               二的三十一次方是2147483648,也就是等于int 的最大的表示范围;因为int 是4个字节,每个字节8个bit位置,最高位是符号位,还剩余31位置。

               |  整除符号;

               a|b   a可以整除b==b除以a余数数0;

               若a|b则b/a|b,b/a可以整除b;

               可知:约数是成对出现的,我们可以枚举较小的数字。

               即判断条件  i<=N/i;  等于号是为了对于完全平方数。

              可以等价于 i<=sqrt(N);但是不推荐,因为sqrt()特别慢。

bool is_prime(int n)
{
    if(n<2)return false ;
    for(int i=2;i<=sqrt(n);i++)
       if(n%i==0)return false;
       return true;
}

             

               还可以等价于i*i<=N;也不推荐,当N~int的值 ,正常的思维i*i<N,(i+1)*(i+1)>N;

   但是(i+1)*(i+1)的结果依然是放到了int的整形里,在这个整形结果的范围里边超出int的范围,会     溢出,(i+1)*(i+1)符号位发生变换,成为负数。从而运行超时。

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

标准结果:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int n,a;

bool is_prime(int n)
{
    if(n<2)return false ;
    for(int i=2;i<=n/i;i++)
       if(n%i==0)return false;
       return true;
}

int main()
{
    scanf("%d",&n);
    while (n -- ){
        scanf("%d",&a);
        if(is_prime(a))puts("Yes");
        else puts("No");
    }
    return 0;
}

(2)分解质因数——试除法 

2.1时间复杂度O(N)

void divide(int x)
{
    if(x<2)return ;
    for(int i=2;i<=x/i;i++)
    {
        int s=0;
        while(x%i==0)
        {
            x/=i;
            s++;
        }
        if(s!=0)
        printf("%d %d\n",i,s);
        
    }
    if(x>1)printf("%d %d\n",x,1);
    puts("");
}

2.2时间复杂度O(sqrt(N))

优化原因:

n中最多只有一个大于sqrt(n)的因子,可能不存在。  if(x>1)printf("%d %d\n",x,1);就是判断是否存在.

#include <iostream>
#include <cstring>
#include <algorithm>
#include<cstdio>

using namespace std;

int n,a;

void divide(int x)
{
    if(x<2)return ;
    for(int i=2;i<=x/i;i++)
    {
        int s=0;
        while(x%i==0)
        {
            x/=i;
            s++;
        }
        if(s!=0)
        printf("%d %d\n",i,s);
        
    }
    if(x>1)printf("%d %d\n",x,1);
    puts("");
}

int main()
{
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d",&a);
        divide(a);
    }
    return 0;
}

for(int i=2;i<=N/i;i++)就是2到sqrt(N)遍历优化的最好方式。

(3)筛质数(给出一个N,求出1~N中质数的个数以及对应数值)

3.1 朴素筛法时间复杂度O(NlogN)

时间复杂度分析:假设一共有n个数据

n/2+n/3+n/4+......n=n(1/2+1/3+1/4+1/5+.....+1/n);

1/2+1/3+1/4+1/5+.....+1/n  调和级数极限lnn+c;

n/2+n/3+n/4+......n=n(1/2+1/3+1/4+1/5+.....+1/n)=nlnn+c<nlogn+c

lg 以10为底  

log 以2为底;

ln 以e为底

时间复杂度O(nlogn)

原因:从小开始,如果他的倍数a存在里边,那么就是a就是存在两个因子不是质数。

从小打到大,最外层从2开始到n,最外层的每一个数值,对应的筛选出他的倍数,为合数。

怎么筛选倍数呢,a 2a  3a 4a .....<=n

设一个j等于i+i,每次下一个倍数 就是j+=i,前提就是j<=x;

void get_prime(int x)
{
    for(int i=2;i<=x;i++)
    {
        if(!st[i])
            prime[++cnt]=i;
        for(int j=i+i;j<=x;j+=i)st[j]=true;
    }
}

  

3.2 埃氏筛法O(NloglogN)

时间复杂度:

素数定理:不超过 x 的素数的个数近似为x / In(x)

N个数计算NlnN次,实际需要计算N/lnN个数,相差了lnN倍。所以使用NlnN/lnN得到大致O(N)

实际的情况式NlonglongN

优化的原因:筛选的时候会有重复的,如果a式b的质因子 ,那么a筛选的数字包括着b筛选的数字。所以合数不需要筛选,只有质数筛选。合数是由之前的质数筛选出来的。

eg:n=16

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

a=2  a在筛选的时候式2 4 6 8 10 12 14 16

b=4  b在筛选的时候4 8 11 16

总结暴力筛选和埃式筛法核心代码就差一个顺序,一个是式在if(!st[i])外边,一个是在里边。

但实际上时间差将近3倍。

void get_prime(int x)
{
    for(int i=2;i<=x;i++)
    {
        if(!st[i])
        {
            prime[++cnt]=i;
            for(int j=i+i;j<=x;j+=i)st[j]=true;
                
        }
    }

 

3.3线性筛法O(N)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值