**小白总结的求素数方法**

判断素数在算法问题中经常遇到,这里编者小白小结了几种求素数的常用方法。
【枚举法】
首先,第一种最常用的方法,便是从1-n逐个判断是否为素数,即逐个判断一个数是否能被2~n-1整除,利用跳出循环时除数与被除数是否相等判断是否为素数。

#include<stdio.h>
int main()
{
   int n,m,i;
   scanf("%d",&n);
   for(m=1;m<=n;m++)
    {
      for(i=2;i<m;i++)
        if(m%i==0)break;
      if(i==m)printf("%d\n",m);
    }
    return 0;
}

基于该种方法,我们可以对其做一些改进:
1.若一个数n不能被2~√n整除,该数即为素数 ;
2.除2之外的偶数均不为素数。

#include<stdio.h>
#include<math.h>
int main()
{
   int n,m,i;
   scanf("%d",&n);
   if(n>=2)printf("%d\n",2);//2做特殊处理
   for(m=3;m<=n;m+=2)//偶数除2均不为素数
    {
      for(i=2;i<=(int)sqrt(m);i++)//优化算法,减少循环次数
        if(m%i==0)break;
      if(i>(int)sqrt(m))printf("%d\n",m);
    }
    return 0;
}

【筛法】
接下来第二种方法就是筛法,筛法的基本思路如下:
(1)挖去1:
(2)用下一个未被挖去的数m去除m后面各数,把m的倍数挖掉;
(3)检查m是否小于n的开方的整数部分,如果是,则返回(2)继续执行,否则就结束;
(4)剩下的数就是素数。
附上一张图片帮助大家理解
在这里插入图片描述

//筛法求素数:素数的倍数一定不是素数
#include<stdio.h>
#include<math.h>
int main()
{
   int n,m,i,x,a[100000];
   scanf("%d",&n);
   x=sqrt(n);
   for(m=1;m<=n;m++)//赋初始值
       a[m]=m;
   a[1]=0;//挖去1
   for(m=2;m<=x;m++)
   {
       for(i=m+1;i<=n;i++)
           if(a[m]!=0&&a[i]!=0)//用下一个未被挖去的数挖去该数的倍数
               if(a[i]%a[m]==0)
                   a[i]=0;
   }
   for(i=1;i<=n;i++)
       if(a[i]!=0)//剩下的数即为素数
           printf("%d\n",a[i]);
   return 0;
}

【六素数法】

在写最后一种方法之前,先给大家介绍一下孪生素数(间隔为2的相邻素数)
推论:当n>=6时,n-1和n+1为孪生素数,那么n一定为6的倍数。

证明如下:

 n-1与n+1是素数,也即n−1和n+1是奇数
∴n是偶数,n是2的倍数。
设n不是3的倍数,即n=3k+1或n=3k+2。
(i)当n=3k+1时,那么n−1=3k,已经与n−1是素数矛盾。
(ii)当n=3k+2时,那么n+1=3(k+1),已经与n+1是素数矛盾。
综上所述,n是3的倍数。
∵n既是2的倍数,又是3的倍数
∴n是6的倍数。

基于此,我们可以把6x(x>=1)附近的数用以下方式表示:

......(6x−1),6x,6x+1,2(3x+1),3(2x+1),2(3x+2),6x+5,6(x+1)......

不在6x两侧的数为:2(3x+1),3(2x+1),2(3x+2),显然它们一定不是素数,所以素数出现在6x的两侧,但在6x两侧的数不一定是素数。(即n>=5时,如果n为素数,则n%6= =1||n%6= =5)

有了以上的理论基础,我们便可以写最后一种方法(六素数法):首先不在6x左右的数2特殊处理,3单独处理,接下来只要判断6x两侧的数是否为素数。因为合数总是可以写成素数的乘积,那么我们直接用n去除以素数就可以达到很好地优化目的。而素数一定是6x两侧的数,且6x两侧的数是大于素数的集合,因此可以用n除以6x两侧的数,即if(n%i==0||n%(i+2)==0)时,不是素数。

//六素数法
#include<stdio.h>
#include<math.h>
int main()
{
     int n,i,flag=1;
     scanf("%d",&n);
     if(n>=2)printf("2\n");//2作特殊处理
     for(int i=3;i<=n;i+=2)
      {
        if(i==3)//3单独处理
            printf("3\n");
        if(i%6!=1&&i%6!=5)
            continue;//不是6x两侧的数不是素数
        for(int j=5;j<=(int)sqrt(i);j+=6)//对6x两侧的数进行判断
            if(i%j==0||i%(j+2)==0)
               {flag=0;break;}
            if(flag==0)
               {flag=1;continue;}
        printf("%d\n",i);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值