质数(prime number)又称素数,有无限个。一个大于1的自然数,除了1和它本身外,不能被其他自然数(质数)整除,换句话说就是该数除了1和它本身以外不再有其他的因数;否则称为合数。

——百度百科

要想判断一个数是不是质数,就要看他能不能被除了1和自己之外的数分解

显然如果当需要多次判断数据是否是素数时,每次都计算一次是很慢的。

但是可以声明一个布尔型数组,保存对应下标是否为素数,这样只需要计算一次。

开始时,从2开始,分别乘上2以上的数,所得的数全都不是素数

以下部分证明有误

#include <iostream>
#include <string>
#include <cstring>
using namespace std;
bool is_prime[10001];
int main(){
    memset(is_prime,true,sizeof(is_prime));
    for(int i=2;i<=100;i++){
        for(int j=2;j<=100;j++){
            is_prime[i*j]=false;
        }
    }
//    printf("%d",is_prime[4]);
    int num;
    //cin>>num;
    for (num=2;num<100;num++){
    if(is_prime[num]==true){
        cout<<num<<"是素数"<<endl;
    }else{
        cout<<num<<"不是素数"<<endl;
    }
    }
    return 0;
}

显然,对于12,这样既计算了26,也计算了62(还有34,43),所以这样重复计算了大量数据

修改一下算法,可以让运算量稍小。

合数可以分解成质数相乘,而根据算法,如果一个合数已经被确定,那么由它得出的合数也都被确定。

所以,如果发现一个数是合数,那么就不必再计算由它乘出的数

同时,保证相乘的两个数都是前一个小后一个大,这样可以避免同一组数的重复计算。

Eratosthenes筛法

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=10000;
bool is_prime[maxn+1];
int main(){
    int m=sqrt(maxn+0.5);
    memset(is_prime,true,sizeof(is_prime));
    for(int i=2;i<=m;i++){
        if(is_prime){
            for(int j=i*i;j<=maxn;j+=i){
                is_prime[j]=false;
            }
        }
    }

    for(int num=2;num<100;num++){
        if(is_prime[num]==true){
            cout<<num<<"是素数"<<endl;
        }else{
            cout<<num<<"不是素数"<<endl;
        }
    }
    return 0;
}

然而,如果我们添加一个count变量来记录每个数被重复运算的次数。会发现,仍然有好多数被重复运算。

不过,线性的算法还是存在的

算术基本定理可表述为:任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积N=P1a1P2a2P3a3......Pnan,这里P1<P2<P3......<Pn均为质数,其中指数ai是正整数。这样的分解称为 N 的标准分解式。最早证明是由欧几里得给出的,现代是由陈述证明。此定理可推广至更一般的交换代数和代数数论。

——百度百科

只需要计算出所有 i×(小于i的素数) ,那么我们便可以得到所有的合数。同时,通过排除掉i是(小于i的素数)的整倍数的情况来保证只计算一次

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=10000;
int main(){
    int count[maxn+1]={0};

    int prime[maxn]={0},num_prime=0;
    bool isNotPrime[maxn]={1,1};

    for(long i=2;i<maxn;i++){
        if(!isNotPrime[i])prime[num_prime++]=i;
        for(int j=0;j<num_prime&&i*prime[j]<maxn;j++){
            isNotPrime[i*prime[j]]=true;
            count[i*prime[j]]++;
            if(!(i%prime[j]))break;
        }
    }

    for(int num=1;num<100;num++){
        if(isNotPrime[num]!=true){
            cout<<num<<"是素数"<<endl;
        }else{
            cout<<num<<"不是素数"<<endl;
        }
    }

    for(int i=1;i<=maxn;i++)if(count[i]>1)cout<<i<<":"<<count[i]<<endl;
    return 0;
}