筛选法求素数,之前我学到的是这个版本:
这种已经非常不错的程序是求1~n之间的素数:
#include<bits/stdc++.h>
using namespace std;
bool a[50000000];
int main()
{
memset(a,1,sizeof(a));
int n;
cin>>n;
for(int i=2;i*i<=n;i++){
if(a[i]) for(int j=2;i*j<=n;j++) a[i*j]=0;
}
for(int i=2;i<n;i++) if(a[i]) cout<<i<<" ";
cout<<endl;
return 0;
}
这种方法将会比一个一个求快数十倍。
但这种方法在最劣情况下时间复杂度将高达O(n*sqrt(n)) 如果n非常大,也依旧是一大笔时间开销。
在优化中,很明显可以看出这种方法中有些合数被筛了不止一遍,有没有方法可以避免这种情况呢?
答案是肯定的,请看这个程序:
#include<bits/stdc++.h>
using namespace std;
bool a[10000000];
int b[10000000];
int n;
void prime1(){
memset(a,1,sizeof(a));
int x=0;
for(int i=2;i<=n;i++){
if(a[i]) b[x++]=i;
int y=0;
while(y<x&&y*i<n){
a[b[y]*i] = 0;
if(i%b[y]==0) break;
y++;
}
}
for(int i=0;i<x;i++) cout<<b[i]<<" ";
cout<<endl;
}
int main()
{
cin>>n;
prime1();
return 0;
}
这个程序无论什么情况下时间复杂度将被限制在O(n) 在n非常大的情况下自然是比第一种快很多。(在n=1000时,将会快十几毫秒,但在n=10000时,将会快两倍)。
这种新的方法同时会拥有许多附加信息,这些信息可以帮助我们求欧拉函数。