zoukankan      html  css  js  c++  java
  • 筛法求素数(2015.7.30)

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

    ——百度百科

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

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

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

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

     

    此部分证明有误

     1 #include <iostream>
     2 #include <string>
     3 #include <cstring>
     4 using namespace std;
     5 bool is_prime[10001];
     6 int main(){
     7     memset(is_prime,true,sizeof(is_prime));
     8     for(int i=2;i<=100;i++){
     9         for(int j=2;j<=100;j++){
    10             is_prime[i*j]=false;
    11         }
    12     }
    13 //    printf("%d",is_prime[4]);
    14     int num;
    15     //cin>>num;
    16     for (num=2;num<100;num++){
    17     if(is_prime[num]==true){
    18         cout<<num<<"是素数"<<endl;
    19     }else{
    20         cout<<num<<"不是素数"<<endl;
    21     }
    22     }
    23     return 0;
    24 }

    显然,对于12,这样既计算了2*6,也计算了6*2(还有3*4,4*3),所以这样重复计算了大量数据

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

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

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

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

     Eratosthenes筛法

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cmath>
     4 using namespace std;
     5 const int maxn=10000;
     6 bool is_prime[maxn+1];
     7 int main(){
     8     int m=sqrt(maxn+0.5);
     9     memset(is_prime,true,sizeof(is_prime));
    10     for(int i=2;i<=m;i++){
    11         if(is_prime){
    12             for(int j=i*i;j<=maxn;j+=i){
    13                 is_prime[j]=false;
    14             }
    15         }
    16     }
    17 
    18     for(int num=2;num<100;num++){
    19         if(is_prime[num]==true){
    20             cout<<num<<"是素数"<<endl;
    21         }else{
    22             cout<<num<<"不是素数"<<endl;
    23         }
    24     }
    25     return 0;
    26 }

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

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cmath>
     4 using namespace std;
     5 const int maxn=10000;
     6 bool is_prime[maxn+1];
     7 int main(){
     8     int count[maxn+1];
     9     memset(count,0,sizeof(count));
    10 
    11     int m=sqrt(maxn+0.5);
    12     memset(is_prime,true,sizeof(is_prime));
    13     for(int i=2;i<=m;i++){
    14         if(is_prime){
    15             for(int j=i*i;j<=maxn;j+=i){
    16                 is_prime[j]=false;
    17                 count[j]+=1;
    18             }
    19         }
    20     }
    21 
    22     for(int num=1;num<100;num++){
    23         if(is_prime[num]==true){
    24             cout<<num<<"是素数"<<endl;
    25         }else{
    26             cout<<num<<"不是素数"<<endl;
    27         }
    28     }
    29 
    30     for(int i=1;i<=maxn;i++)if(count[i]>1)cout<<i<<":"<<count[i]<<endl;
    31     return 0;
    32 }
    点击查看

     

    但是是存在线性的筛法的

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

    ——百度百科

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

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cmath>
     4 using namespace std;
     5 const int maxn=10000;
     6 int main(){
     7     int count[maxn+1]={0};
     8 
     9     int prime[maxn]={0},num_prime=0;
    10     bool isNotPrime[maxn]={1,1};
    11 
    12     for(long i=2;i<maxn;i++){
    13         if(!isNotPrime[i])prime[num_prime++]=i;
    14         for(int j=0;j<num_prime&&i*prime[j]<maxn;j++){
    15             isNotPrime[i*prime[j]]=true;
    16             count[i*prime[j]]++;
    17             if(!(i%prime[j]))break;
    18         }
    19     }
    20 
    21     for(int num=1;num<100;num++){
    22         if(isNotPrime[num]!=true){
    23             cout<<num<<"是素数"<<endl;
    24         }else{
    25             cout<<num<<"不是素数"<<endl;
    26         }
    27     }
    28 
    29     for(int i=1;i<=maxn;i++)if(count[i]>1)cout<<i<<":"<<count[i]<<endl;
    30     return 0;
    31 }

    运行后,可以发现没有每个数运行次数都是1

  • 相关阅读:
    nginx-1.8.1的安装
    ElasticSearch 在3节点集群的启动
    The type java.lang.CharSequence cannot be resolved. It is indirectly referenced from required .class files
    sqoop导入导出对mysql再带数据库test能跑通用户自己建立的数据库则不行
    LeetCode 501. Find Mode in Binary Search Tree (找到二叉搜索树的众数)
    LeetCode 437. Path Sum III (路径之和之三)
    LeetCode 404. Sum of Left Leaves (左子叶之和)
    LeetCode 257. Binary Tree Paths (二叉树路径)
    LeetCode Questions List (LeetCode 问题列表)- Java Solutions
    LeetCode 561. Array Partition I (数组分隔之一)
  • 原文地址:https://www.cnblogs.com/ohyee/p/4689610.html
Copyright © 2011-2022 走看看