资源描述:
《求素数的算法及其复杂度分析》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
1、求素数的算法及其复杂度分析2008-04-0517:46关于搜寻一定范围内素数的算法及其复杂度分析——曾晓奇关于素数的算法是信息学竞赛和程序设计竞赛中常考的数论知识,在这里我跟大家讲一下寻找一定范围内素数的几个算法。看了以后相信对大家一定有帮助。正如大家都知道的那样,一个数n如果是合数,那么它的所有的因子不超过sqrt(n)--n的开方,那么我们可以用这个性质用最直观的方法来求出小于等于n的所有的素数。num=0;for(i=2;i<=n;i++){for(j=2;j<=sqrt(i);j++)if(j%i==0)break;if(j>sqrt(i
2、))prime[num++]=i;//这个prime[]是int型,跟下面讲的不同。}这就是最一般的求解n以内素数的算法。复杂度是o(n*sqrt(n)),如果n很小的话,这种算法(其实这是不是算法我都怀疑,没有水平。当然没接触过程序竞赛之前我也只会这一种求n以内素数的方法。-_-~)不会耗时很多.但是当n很大的时候,比如n=10000000时,n*sqrt(n)>30000000000,数量级相当大。在一般的机子它不是一秒钟跑不出结果,它是好几分钟都跑不出结果,这可不是我瞎掰的,想锻炼耐心的同学不妨试一试~。。。。在程序设计竞赛中就必须要设计出一
3、种更好的算法要求能在几秒钟甚至一秒钟之内找出n以内的所有素数。于是就有了素数筛法。(我表达得不清楚的话不要骂我,见到我的时候扁我一顿我不说一句话。。。)素数筛法是这样的:1.开一个大的bool型数组prime[],大小就是n+1就可以了.先把所有的下标为奇数的标为true,下标为偶数的标为false.2.然后:for(i=3;i<=sqrt(n);i+=2){if(prime[i])for(j=i+i;j<=n;j+=i)prime[j]=false;}3.最后输出bool数组中的值为true的单元的下标,就是所求的n以内的素数了。原理很简单,就是
4、当i是质(素)数的时候,i的所有的倍数必然是合数。如果i已经被判断不是质数了,那么再找到i后面的质数来把这个质数的倍数筛掉。一个简单的筛素数的过程:n=30。123456789101112131415161718192021222324252627282930第1步过后24...2830这15个单元被标成false,其余为true。第2步开始:i=3;由于prime[3]=true,把prime[6],[9],[12],[15],[18],[21],[24],[27],[30]标为false.i=4;由于prime[4]=false,不在继续筛法步
5、骤。i=5;由于prime[5]=true,把prime[10],[15],[20],[25],[30]标为false.i=6>sqrt(30)算法结束。第3步把prime[]值为true的下标输出来:for(i=2;i<=30;i++)if(prime[i])printf("%d",i);结果是2357111317192329这就是最简单的素数筛选法,对于前面提到的10000000内的素数,用这个筛选法可以大大的降低时间复杂度。把一个只见黑屏的算法优化到立竿见影,一下就得到结果。关于这个算法的时间复杂度,我不会描述,没看到过类似的记载。只知道算法
6、书上如是说:前几年比较好的算法的复杂度为o(n),空间复杂度为o(n^(1/2)/logn).另外还有时间复杂度为o(n/logn),但空间复杂度为O(n/(lognloglogn))的算法。我水平有限啦,自己分析不来。最有说服力的就是自己上机试一试。下面给出这两个算法的程序://最普通的方法:#include#include#defineN10000001intprime[N];intmain(){inti,j,num=0;for(i=2;i7、i==0)break;if(j>sqrt(i))prime[num++]=i;}for(i=2;i<100;i++)//由于输出将占用太多io时间,所以只输出2-100内的素数。可以把100改为Nif(prime[i])printf("%d",i);return0;}//用了筛法的方法:#include#include#defineN10000001boolprime[N];intmain(){inti,j;for(i=2;i8、e;for(i=3;i<=sqrt(N);i++){if(prime[i])for(j=i+i;j