这篇文章我们将讨论有关如何求解素数,
素数:即只能被1及其本身整除的数。
方法一:暴力判断
对于一个数N是不是素数,可以通过2~n-1—进行枚举,如果n不能被整除,那么说明n就是素数。
/*注意两点:①n不能太大。②只需要判断n的根号次。*/
下面是判定素数的源代码:
#include <cmath> int IsPrime(int n) { for(int i=2; i<=sqrt(1.0*n); ++i) if(n%i == 0) return 0; return 1; }
很明显这样直接枚举判断的时间复杂度很高,下面讲一种高效的方法:筛法,如果用筛法构造素数,可以在很短的时间内算出10^6以内的所有素数。
方法二:筛法
筛法的原理简单来说就是删除倍数,即对于不超过n的每一个非负整数p,删除2p,3p,4p,.....,这样处理完每一个p之后,剩下的没有被删除的就是素数,其实这也是素数定义的体现,即能被除了1和自身外的任何数整除的数都不是素数。
时间复杂度:nlog(n)
下面是筛法的源代码:
#include <cmath> #include <cstring> constint MAXN = 1e6; int vis[MAXN+1]; int prime[MAXN+1]; void IsPrime(int n) { int i, j; int m = sqrt(n+0.5); memset(vis, 0, sizeof(vis)); memset(prime, 0, sizeof(prime)); for(i=2; i<=m; ++i) if(!vis[i]) { prime[i] = 1; // 如果i为素数 for(j=i*i; j<=n; j+=i) vis[j] = 1; } for(; i<=n; ++i) if(!vis[i]) prime[i] = 1; }
以上算法并不是最快的,因为存在重复的筛数,比如2和4来说,都将8,12,16,……,筛除了。要保证不会重复筛除每一个数,即让算法保持线性,可以从奇偶性方面入手。
const int MAXN = 1e6; int prime[MAXN+1]; void IsPrime(int n) { int i,j,k; int half = n/2; int sn = sqrt(n+0.5); memset(prime,0,sizeof(prime)); for (i = 0; i < half; i++) prime[i] = 1; for (i = 0; i < sn; i++) if(prime[i]) { for(k=i+i+3,j=k*i+k+i; j<half; j+=k) prime[i] = 0; } }