素数打表法(四种方法)

1.手动打表

当需要的数据范围较小时,比如下面的40个

int prime[40]={0,1,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0};
//素数打表,因为n最大是20,所以只要打到40

2.按定义(耗时长)

最基本的方法是通过素数的定义直接判断,只能被1和它本身整除的数就是素数了。这种方法适合判断单个数是否为素数,当要求一个范围内素数而这个范围又比较大时,这种方法就不太使用了,甚至程序要运行几分钟才能算出结果。

int i,n,x;
  while(scanf("%d",&n)!=EOF)
  {
    x=(int)sqrt(n);
    for(i=2;i<=x;i++)
    if(n%i==0)    break; 
    if(i>x)    printf("YES\n");
    else       printf("NO\n");
  }

3.普通筛选法求素数

出现一个数,则把已这个数为因子的数都标记为合数。

如2,所以4,6,8 10....都标记为合数

如3,所以9,12,15.....都标记为合数

如4,所以16,20,24...都标记为合数

即,若i是素数,则从 j=i*i 开始,把 j+i , j+2i , j+3i .....都标记为合数 (因为2*i , 3*i,4*i,....(i-1)*i 分别是2,3,4,...i-1的的倍数,已经在i之前标记过,所以从j=i*i开始标记)

筛法的思想是去除要求范围内所有的合数,剩下的就是素数了,而任何合数都可以表示为素数的乘积,因此如果已知一个数为素数,则它的倍数都为合数。

int main()
{
    int n=100;
    int a[100000]={0};
    int m=sqrt(n+0.5);
 
    for(int i=2;i<=m;i++) if(!a[i])
        for(int j=i+i;j<=n;j+=i) a[j]=1;
 
    for(int i=2;i<=n;i++)
        if(!a[i]) printf("%d ",i);
    return 0;
}

版本二:

素数筛法是这样的:
   1.开一个大的bool型数组prime[],大小就是n+1就可以了.先把所有的下标为奇数的标为true,下标为偶数的标为false.
   2.然后:
      for( i=3; i<=sqrt(n); i+=2 )
      {   if(prime)
          for( j=i+i; j<=n; j+=i ) prime[j]=false;
      }
    3.最后输出bool数组中的值为true的单元的下标,就是所求的n以内的素数了。

int prime[N];
int main()
{
   int i, j;
   for(i=2; i<N; i++)
  {
       if(i%2) prime[i]=1;
       else prime[i]=0;
   }

   for(i=3; i<=sqrt(N); i++)
   {    
       if(prime[i]==1)
       for(j=i+i; j<N; j+=i) 
       prime[j]=0;
   }

   for(i=2; i<100; i++)//只输出2-100内的素数
    if( prime[i]==1 )printf("%d ",i);
   printf("\n");

   return 0;
}

 4.注意!!!!!!!

高效筛选法求素数(我是通过九九乘法表想通的(*^▽^*))

普通的线性筛法虽然大大缩短了求素数的时间,但是实际上还是做了许多重复运算,比如2*3=6,在素数2的时候筛选了一遍,在素数为3时又筛选了一遍。如果只筛选小于等于素数i的素数与i的乘积,既不会造成重复筛选,又不会遗漏。时间复杂度几乎是线性的。

   /*
遇到素数需要打表时,先估算素数的个数:
num = n / lnx;
num为大概数字,越大误差越小(只是估计,用于估算素数表数组大小)
这个打表法效率貌似很高,网上说几乎达到了线性时间(不知道是真是假=。=)
*/
    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    #include<stdlib.h>
    #define maxn 10000000
    bool visit[maxn+1000000];
    int prime[maxn],n; ///prime的大小大概估计一下再开数组。大概是(x/lnx)
    void getprime()
    {
        memset(visit, false, sizeof(visit));
        int num = 0;
        for (int i = 2; i <= n; ++i)
        {
            if ( !visit[i] )  prime[++num] = i;
            for (int j = 1; j <= num && i * prime[j] <= n ;  j++)
            {
                visit[ i  *  prime[j] ]  =  true;
                if (i % prime[j] == 0) break; //此处是重点,避免了很多的重复判断,比如i=9,现在素数是2,3,5,7,进入二重循环,visit[2*9]=1;visit[3*9]=1;这个时候9%3==0,要跳出。因为5*9可以用3*15来代替,如果这个时候计算了,i=15的时候又会被重复计算一次,所以这里大量避免了重复运算。
            }
        }
    }
    int main()
    {
        scanf("%d",&n);
        getprime();
        return 0;
    }

猜你喜欢

转载自blog.csdn.net/qq_42079027/article/details/81410361