题目要求:统计出从1到n中的素数个数
1.最原始的做法
依次遍历每个数,每拿到一个数,对它进行判断,如果是素数,则标记并统计。时间复杂度O(n * sqrt(n))。
2.简单筛选法
1)将所有prime[i]标记为1(prime[i]=1代表i是素数,先全部标记为1,后面逐步排除合数)
2)挑出第一个素数(prime[i]=1),并用该素数i排除在n范围内i的所有倍数
举例说明n=10的情况
i = 2, 则需要排除2的倍数4,6,8,10(这些必然不是素数)
i = 3, 则需要排除3的倍数6,9
i = 5,则需要排除5的倍数10
此处,有两个问题
①这样能保证排除所有的合数吗?
答案是肯定的。假设A是不超过n的合数,假设A=B*C(B<C),若B是素数,则说明通过B可排除A,若B是合数,则B一定可以继续分解,如B=D*E(D<E),直到第一个数为素数为止。
②在简单筛选法的步骤2)中,i需要到多大,才能排除所有非素数?
答案是sqrt(n),采用反证法,如果A是小于n的合数,且A>sqrt(n),A=B*C(B和C一定有一个数小于sqrt(n)),根据理论①,如果B,C至少有一个合数,则一定可以继续拆,拆成第一个数是素数的形式,这样它一定会被那个素数排除掉。
先献上代码,后面还有一种优化后续再写
#include <iostream>
#include <cmath>
#include <memory.h>
#define MAX 10000
using namespace std;
int isPrime(int n)
{
int cnt = 1;
// cout<<2<<" ";
for(int i = 3; i <= n; i++)
{
int temp = sqrt(i * 1.0);
int j = 2;
for(; j <= temp; j++)
{
if(i % j ==0)
break;
}
if(j > temp)
{
cnt++;
// cout<<i<<" ";
}
}
//cout<<endl;
return cnt;
}
int simpleIsPrime(int prime[],int n)
{
int cnt= 1; //非素数个数cnt标记为1(因为要从2开始筛选,1不是素数,所以将cnt置为1)
memset(prime,sizeof(prime) * (n + 1),1);
int temp = sqrt(n * 1.0);
for(int i = 2; i <= temp; i++)
{
if(prime[i])
{
// int temp = sqrt(i * 1.0);
for(int j = 2 * i; j <= n; j = j + i)
{
if(prime[j])
{
cnt++;
prime[j] = 0;
}
}
}
}
return n - cnt;
}
int main()
{
int n;
cin>>n;
// bool prime[];
int prime[MAX];
cout<<isPrime(n)<<endl;
cout<<simpleIsPrime(prime,n)<<endl;
return 0;
}