筛法求素数

来源:互联网 发布:js图片旋转,收缩 编辑:程序博客网 时间:2024/06/05 18:38

求解素数有多种方法,其中最著名的就是筛法求素数。现在从最朴素的算法开始一步一步的不断优化,体会算法的不断发展。

1)枚举法求素数

这种算法最基础,但是效率也最低,复杂度O(N*logN),数据量一大就不行了。

我们知道一个数若为合数,则其因子不超过int(sqrt(double(N))),可以利用这个性质枚举N以内的所有数,确定素数。

代码:

void Get_prime1(int n){int *prime=new int[n];int i,j,pivot=0;for(i=2;i<=n;i++){for(j=2;j<=int(sqrt(double(i)));j++)if(i%j==0) break;if(j>int(sqrt(double(i))))prime[pivot++]=i;}for(i=0;i<pivot;i++)    printf("%d ",prime[i]);printf("\n");delete []prime;}

2)筛法求素数

我们知道一个素数的倍数必定为合数。那么可以根据这个特征,利用已知的素数筛掉其倍数(合数),筛法求素数的核心思想就是如此。

代码:

void Get_prime2(int n){bool *prime=new bool[n+1];memset(prime,1,sizeof(prime));    int i,j;for(i=2;i<=int(sqrt(double(n)));i++)if(prime[i]){for(j=i<<1;j<=n;j+=i)prime[j]=0;}for(i=2;i<=n;i++)if(prime[i])printf("%d ",i);    printf("\n");delete []prime;}

3)优化筛法求素数

对于N以内的素数,我们知道偶数必定不是素数,所以可以最开始就将偶数排除,用数组只记录N以内的奇数,然后对该数组采用筛法思想。这样时间较上述算法快了一倍多。

代码:

void Get_prime3(int n){int *prime=new int[n>>1];bool *flag=new bool[n>>1];int i,j,pivot=0;for(i=3;i<=n;i+=2)prime[pivot++]=i;memset(flag,1,pivot);for(i=0;prime[i]<=int(sqrt(double(n)));i++)if(flag[i]){for(j=i+1;j<pivot;j++)if(prime[j]%prime[i]==0)flag[j]=0;}printf("2 ");for(i=0;i<pivot;i++)if(flag[i])printf("%d ",prime[i]);printf("\n");delete []prime;delete []flag;}

4)在3)基础上减少重复筛除的次数

通过实验可以发现,内层循环可以从下标为i*(i*2+6)+3的数据开始筛除。减少了循环个数,较3)也有了很大的时间复杂度优化提升。

代码:

void Get_prime4(int n){int *prime=new int[n>>1];bool *flag=new bool[n>>1];int i,j,pivot=0;for(i=3;i<=n;i+=2)prime[pivot++]=i;memset(flag,1,pivot);for(i=0;prime[i]<=int(sqrt(double(n)));i++)if(flag[i]){for(j=i*((i<<1)+6)+3;j<pivot;j++)if(prime[j]%prime[i]==0)flag[j]=0;}printf("2 ");for(i=0;i<pivot;i++)if(flag[i])printf("%d ",prime[i]);printf("\n");delete []prime;delete []flag;}

更加优化的算法(今天做题用上面第四种方法总TLE,后来看某牛的算法,然后自己写了个测试程序,看运行时间,结果吓呆了,自己还是太嫩了,完全无法与这种方法相提并论)

代码:

int prime[Max];void Get_prime(int n){    int pivot=0;prime[pivot++]=2;for(int i=3;i<=n;i+=5){int flag=true;for(j=0;prime[j]*prime[j]<=i;j++)if(i%prime[j]==0){flag=false;break;}if(flag)prime[pivot++]=i;}}

测试程序(时间如下):

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<math.h>#include<ctime>#define Max 110#define Maxx 500010using namespace std;int prime[Maxx];bool flag[Maxx];/*void Get_prime(int n){clock_t start, finish; //建立对象double totaltime;start = clock(); //clock():Current time of CPU,当前的时间int i,j,pivot=0;for(i=3;i<=n;i+=2)prime[pivot++]=i;memset(flag,1,pivot);for(i=0;prime[i]<=int(sqrt(double(n)));i++)if(flag[i]){for(j=i*((i<<1)+6)+3;j<pivot;j++)if(prime[j]%prime[i]==0)flag[j]=0;}finish=clock();//现在的时间totaltime=(double)(finish-start)/CLOCKS_PER_SEC; //现在的时间-设置的初始时间=程序运行的时间,转化为s    printf("Runtime is: %lf s\n",totaltime);//num=pivot;}*/void PrimeTable(int n)  {      int pNum=0;      prime[pNum++]=2;      for(int i=3;i<=n;i+=2)  //奇偶法       {          bool flag=true;          for(int j=0;prime[j]*prime[j]<=i;j++)  //根号法+递归法               if(!(i%prime[j]))              {                  flag=false;                  break;              }          if(flag)              prime[pNum++]=i;      }  //num=pNum;    //return;  }  int main(){return 0;}

主程序测试:

int main(){scanf("%d",&n);Get_prime1(n);Get_prime2(n);Get_prime3(n);Get_prime4(n);return 0;}
0 0
原创粉丝点击