几种素数筛法

  素数的求解是数论题目中频繁遇到的问题,下面介绍几种求 n 以内的素数的算法

全局定义:

1 const int n = ?;        //n范围
2 const int ma = ?;        //素数个数
3 bool nu[n];            //标记数组
4 int phi[ma];            //存素数
5         

 

1、较为高效的筛法

  思想:从 2 开始,即标记数组为0(或为1),当标记数组为 0(或1) 时,该数为素数,把素数的倍数筛掉。此算法缺陷在于会重复筛选有不同素数因子的合数(比如说6,被2筛一次,又被3筛一次)

代码:

 1 void prime1()            //因为标记的时候会出现大量重复
 2 {
 3     memset(nu, 0, sizeof(nu));
 4     int k = 0;
 5     for(int i = 2; i < n; ++i)
 6         if(!nu[i])
 7         {
 8             phi[k++] = i;
 9             for(int j = i*i; j < n; j += i)
10                 nu[j] = 1;
11         }
12 }

2、线性筛法

  线性筛法就是为了避免重复筛掉同一个合数。思想是:从2 开始遍历,遇到素数就记录下来,当 i 遍历到为前面已经存储的素数的倍数的时候,就跳出循环,这样不仅可以筛选出所有素数,而且避免了重复。

代码:

 1 void prime2()        //线性筛法
 2 {
 3     memset(nu, 0, sizeof(nu));
 4     int k = 0;
 5     for(int i = 2; i < n; ++i)
 6     {
 7         if(!nu[i])    phi[k++] = i;
 8         for(int j = 0; (j<k && i*phi[j]<n ); ++j)
 9         {
10             nu[i*phi[j]] = 1;
11             if(i%phi[j] == 0)    break;
12         }
13     }
14 }

优化:

优化原理:除了2以外,所有素数都是奇数,所以排除2以后,i 就可以不管偶数了,值得注意的是,排除 2 之后,nu[4] 要清除标记。

代码:

 1 void prime3()    //线性筛法改良
 2 {
 3     memset(nu, 0, sizeof(nu));
 4     int  k = 1;
 5     phi[0] = 2, nu[4] = 1;
 6     for(int i = 3; i < n; i += 2)
 7     {
 8         if(!nu[i])    phi[k++] = i;
 9         for(int j = 0; (j<k && i*phi[j]<n); ++j)
10         {
11             nu[i*phi[j]] = 1;
12             if(i%phi[j] == 0)    break;
13         }
14     }
15 }

 

posted @ 2013-07-24 20:23  妮king狼  阅读(1693)  评论(0编辑  收藏  举报