判断素数的多种方法(PTAL1-028 判断素数解题有感)
今天在写PTA团体程序设计天梯赛-练习集时,被一道简单的判断素数的题给卡住了,试了几种方法都是会有一些测试点超时,遂上网查阅了相关的判断素数的方式,经过多个不同的方法解决题目之后,发现竟然有这么多不同层次的判断素数的方法,遂想记录下自己这么久以来学过的这些判断方法,以供大家参考!
一、最最简单暴力的解法
我们先来看看质数的定义:质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数(规定1既不是质数也不是合数)。所以素数最重要的一点是它只能被1或者它本身整除,所以这里我们可以让
这个整数n被2,3,4…n-1全部除一次,如果中间出现了能被整除的情况,则不是素数。
#include<stdio.h>
int main()
{
int i;//这里以判断1到1000以内的素数为例
int j;
for (i = 1; i <= 1000; i++)
{
int k=1;
for (j = 2; j < i; j++)
{
if (i % j == 0)
k = 0;
}
if (k == 1) printf("%5d ",i);
}
return 0;
}
这是最最基础,最最简单粗暴的方法,得到的结果如下
接下来我们在此基础上做出一些优化
二、一些简单的优化
1.减少遍历的时间
我们先举一个例子,10可以被2合5整除,那么当程序遍历到2和5时的效果是相同的,都可以判断10不是素数,所以我们只要发现能被整除的情况便可退出程序不再遍历,除此之外,如果遇到了素数n,我们也不需要遍历到n-1,只要遍历到n的平方根即可,因为如果在2到根号n之间找不到能整除i的数字,那么在根号n到n-1之间也不会出现能整除i的数字,所以我们可以对程序做出如下优化
#include<stdio.h>
#include<math.h>
int main()
{
int i;//这里以判断1到1000以内的素数为例
int j;
for (i = 1; i <=1000 ; i++)
{
int k = 1;
if (i == 1)
k = 0;
else
{
/*for (j = 2; j*j <= i; j++)//这里是用j*j来保证j不超过根号i
{
if (i % j == 0)
k = 0;
break;
}*/
for (j = 2; j <= sqrt(i); j++)//这里使用库函数来计算出根号i
{
if (i % j == 0)
{
k = 0;
break;//这里是出现整除的情况便不再遍历,退出循环
}
}
if (k == 1) printf("%5d",i);
}
}
return 0;
}
这里我们将使用j*j<=i的这一种方法进行了注释,因为这种方法相对使用库函数来说,每次判断
时都要计算一次,增加了程序运行的时间,所以我们这里只是列出而不推荐使用。
2.使用奇数
我们不难发现这样的规律,除了2以外的偶数一定都不是素数,因为他们至少都可以被2给整除,所以我们可以在遍历之前判断这个数是否是奇数,如果是奇数则遍历,是2以外偶数则直接判断为不是素数,同时我们再遍历的时候也可以进一步简化,因为已经排除了所有的除2以外的偶数,所以我们在遍历的时候也可以跳过偶数了,从3开始,每次递增2,这又可以为计算机节省出一些计算的时间,代码如下
#include<stdio.h>
#include<math.h>
int main()
{
int i;//这里以判断1到1000以内的素数为例
int j;
for (i = 1; i <=1000 ; i++)
{
int k = 1;
if (i == 1||(i%2==0&&i!=2))
k = 0;
else
{
for (j = 3; j <= sqrt(i); j+=2)
{
if (i % j == 0)
{
k = 0;
break;
}
}
if (k == 1) printf("%5d",i);
}
}
return 0;
}
3.再简化版
今天我在网络上浏览的时候,发现了一个有意思的性质,那就是大于等于5的素数,一定是与6及其倍数相邻,所以这里我们又可以对这段代码再进行简化,排除更多的数据
#include<stdio.h>
#include<math.h>
int is_Prime(int k)
{
if (k == 1 || (k >= 5 && (k % 6 != 1 && k % 6 != 5)) || (k % 2 == 0 && k != 2))
return 0;
else
return 1;
}
int main()
{
int i;
int j;
for (i = 1; i <= 1000; i++)
{
int ret = is_Prime(i);
if(ret)
{
int k = 1;
for (j = 3; j <= sqrt(i); j+=2)
{
if (i % j == 0)
{
k = 0;
break;
}
}
if (k == 1)printf("%5d",i);
}
}
return 0;
}
以上便是用简单遍历方法对素数进行判断了,下面我们介绍最后一种,运用数组来判断素数的放大
三、运用数组来判断素数的方法
这里用到我们发现的素数的另一种性质:如果质数n不能被小于n的质数整除,则n就是质数,所以我们这里用数组来存储素数,然后在检验素数的时候,只要拿数组中的素数相除来判断即可,这个代码相对复杂一些,但是非常好用,且需要一定的基础
#include<stdio.h>
int main()
{
int prime[1000]={0};//存储素数的数组
int i,j;
int count = 1;//数组的下标
prime[0] = 2;//先放入第一个素数
for (i = 3; i <= 1000; i++)
{
int k = 1;
for (j = 0; j < count; j++)
{
if (i % prime[j] == 0)
{
k = 0;
break;
}
}
if (k == 1)
{
prime[count] = i;
count++;
}
}
for (i = 0; i < count; i++)
printf("%5d", prime[i]);
return 0;
}
以上便是个人所知的所有的判断素数的方式了,后续应该还会对其有所增加,如果您有什么好的建议或者好的方法,也欢迎您提出来。