genPrime和genPrime2是筛法求素数的两种实现,其实是一个思路,表示方法不同而已。
具体思路在注释中已经含有。
#include<iostream> #include<math.h> #include<stdlib.h> using namespace std; const int MAXV = 100; //素数表范围 bool flag[MAXV+1]; //标志一个数是否为素数 int prime[MAXV+1]; //素数表,下标从0开始 int size=0; //素数个数 void genPrime(int max) { memset(flag, true, sizeof(flag));//首先对标签数组进行初始化,全部设为true。 for(int i = 2; i <= max / 2; i++) { /* 从2开始,删除2的倍数 */ if(flag[i]) { //j=i<<1等价于 j=i*2,即j是i的两倍,而最后的j+=i,则表示下一个循环j是i的3倍,接着4倍。。。 //i的所有2~N倍数肯定都不是素数,因此将flag置为0,直到最后一位。 for(int j = i << 1 ; j <= max; j += i) { flag[j] = false; } } } for(int i = 2 ; i <= max; i++) { if(flag[i]) { prime[size++] = i;//存储素数。将所有标志位依然为1的标志写入素数数组中去。 } } } void genPrime2(int max) { memset(flag, true, sizeof(flag));//首先对标签数组进行初始化,全部设为true。 int sq=sqrt((double)max)+1; //一个数 n 如果是合数,那么它的所有的因子不超过sqrt(n) int i,j, k; for(i = 2;i<=sq; i++) { if(flag[i]) for(j=2,k=max/i+1;j<k;j++) flag[i*j] = false; //所有i的j倍都不是素数 } for( i = 2 ; i <= max; i++) { if(flag[i]) { prime[size++] = i;//存储素数。将所有标志位依然为1的标志写入素数数组中去。 } } } int main() { // genPrime(MAXV); genPrime2(MAXV); //输出所有素数。 for(int i=0;i<size;i++) cout<<prime[i]<<" "; cout<<endl; system("pause"); return 0; } /* 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 请按任意键继续. . . */
ps:补充于2011-6-14
参考博客:
1.http://www.cppblog.com/shyli/archive/2007/05/18/24334.html
2.http://blog.sina.com.cn/s/blog_4b5210840100cm4r.html
3.http://blog.hjenglish.com/bedford/archive/2008/10/11/401082.html
筛法其实就是以空间换时间的一个最好的证明。空间复杂度增加了,时间复杂度降低了。这个斐波那契数列求解类似,如果用递归,那么时间复杂度很慢,如果将用数组存储一个斐波那契数列,则时间复杂度降低到线性。
上面的参考博客2有一些解释,3则给出了具体的改进算法。有空再研究。