筛法求素数

来源:互联网 发布:蜡烛图分析软件 编辑:程序博客网 时间:2024/05/25 21:33

筛法求素数

假设要求n以内的素数

筛法求素数是用一个大小为n的数组,作为标记数组,如果没被标记到则为素数。

开始均为未标记。

从2开始,2没被标记,将2存入一个存素数的地方,然后筛掉小于n的,2的所有倍数。然后是3,筛掉3的所有倍数,依此类推,直到n-1。

优化

上面的做法,同一个数可能会被筛掉多次,比如6会被3和2各筛一次。

为了提高效率,需要进行优化,使得每个数尽可能的被少筛,如果能一次最好。

考虑到任何合数都可以分解成若干个素数的乘积。在筛掉合数的过程中,最好的是让每个合数只被它最小的因子筛掉。

如24 18 都只被2筛掉

C++实现

 int countPrimes(int n) {        vector<bool> vis(n,false);        vector<int> prime;        for(int i=2;i<n;i++){            if(!vis[i]) prime.push_back(i);            for(int j=0;j<prime.size() && i*prime[j]<=n;j++){                vis[i*prime[j]] = true;                if(i%prime[j] == 0) break;  //优化            }        }        return prime.size(); }

最外层循环每次循环,都能得到小于等于i的所有素数,当要求i+1内的素数时,只需判断i+1是否在之前被筛掉。

与此同时,将当前所有素数的i+1倍筛掉。

那后面出现的素数的i+1倍,设为m ,会怎么样呢?

  • 如果i+1是素数,m会被 i+1 筛掉
  • 如果i+1不是素数,则m 会被i+1的最小质因数(之前出现过的素数中的某一个)筛掉。

优化点:每个数都被它最小的因数筛掉

具体操作:如果循环到某个素数 prime[j] 是 i+1的倍数时,后面的素数的i+1倍 prime[j+1] * (i+1) 就不用筛了。

原因在于:后面素数的i+1倍一定会被 prime[j] (更小的一个数)筛掉,

prime[j+1](i+1)=prime[j+1]prime[j]k

k=(i+1)/prime[j]

原创粉丝点击