素数又称为质数,是指除了1和本身之外,不能被其他数整除的一类数。即对给定的正整数n,如果对任意的正整数a(1<a<n),都有n%a!=0成立,那么称n是素数;否则,如果存在a(1<a<n),使得n%a==0,那么称n为合数。应特别注意的是,1既不是素数,也不是合数。
1.判断一个数是不是素数:
程序代码:
#include<cstdio>
#include<cmath>
bool isPrime(int n){
if(n<=1) //特判,素数的范围大于1
return false;
int sqr = (int)sqrt(1.0*n);//根号n
for(int i=2;i<=sqr;i++){ //遍历2~根号n
if(n%i==0)
return false; //n是i的倍数,n不是素数
}
return true; //否则n是素数
}
int main(){
int a;
while(scanf("%d",&a)!=EOF)
printf("%d\n",isPrime(a));
return 0;
}
运行结果:
说明:
在上述代码中,sqrt的作用为一个浮点数取整,需要添加math.h头文件。由于sqrt的参数要求是浮点数,因此在n前面乘以1.0来使其成为浮点型。
时间复杂度:O(sqrt(n))
2.求解100以内的素数:
(1)暴力破解:
程序代码:
#include<cstdio>
#include<cmath>
bool isPrime(int n){
if(n<=1) //特判,素数的范围大于1
return false;
int sqr = (int)sqrt(1.0*n);//根号n
for(int i=2;i<=sqr;i++){ //遍历2~根号n
if(n%i==0)
return false; //n是i的倍数,n不是素数
}
return true; //否则n是素数
}
int main(){
int a;
for(int i=2;i<=100;i++){
if(isPrime(i))
printf("%d\n",i);
}
return 0;
}
运行结果:
时间复杂度:O(n*n^(1/2))
(2)“筛法”
“筛法”是众多筛法中最简单且容易理解的一种,即 Eratosthenes筛法。素数筛法的关键就在一个“筛”字。算法从小到大枚举所有数,对每一个素数,筛去它的所有倍数,剩下的就都是素数了。
可能有读者问,一开始并不知道哪些数是素数,所以我们先要事先确定素数2。当从小到大到达某数a时,如果a没有被前面步骤的数筛去,那么a一定是素数。这是因为,如果a不是素数,那么a一定有小于a的素因子,这样在之前的步骤中a一定会被筛掉,所以,如果当枚举到a时还没有被筛掉,那么a一定是素数。
至于“筛”这个动作的实現,可以使用一个bool型数组p来标记,如果a被筛掉,那么p[a]为true;否则,p[a]为 false。在程序开始时可以初始化p数组全为 false。
程序代码:
#include<cstdio>
const int maxn = 101; //表长
int prime[maxn],pNum=0; //prime数组存放所有素数,pNum为素数个数
bool p[maxn] = {0}; //如果i为素数,则p[i]为false;否则p[i]为true
void Find_Prime() {
for(int i=2;i<maxn;i++) { //从2开始,i<maxn结束,注意i不能等于maxn
if(p[i]==false){ //如果i是素数
prime[pNum++]=i; //把素数i存到prime数组中
for(int j=i;j<maxn;j+=i){ //筛去所有i的倍数,循环条j不能等于maxn
p[j]=true;
}
}
}
}
int main(){
Find_Prime();
for(int i=0;i<pNum;i++){
printf("%d\n",prime[i]);
}
return 0;
}
运行结果:
时间复杂度:O(nloglogn),不必证明
练习题:数素数