素数判断

来源:互联网 发布:淘宝店铺模板怎么用 编辑:程序博客网 时间:2024/05/17 09:36

0.前言

由于最近在刷PAT题,我想想这些天接触到的一些新的知识,列表如下:

(1)如何判断一个数是否为素数?

(2)如何求出一个数字范围内的所有素数?并且使得这个过程尽量高效?


1.假设读者都具有以下的知识:

(1)素数:一个数是素数的条件是:它只能被1和其本身整除。

(2)1不是素数!


2.设计算法
(1)暴力法

我在这里姑且称其为暴力法,其实这是最为笨拙的一中方法,代码如下:

#include <stdio.h> void isPrime(int number){int j ,i = 0 ;for(j = 2;j <= number;j++){for(i = 2;i < j;i++){if(j % i == 0){break;}}if(i == j){printf("%d ",j);}}}int main(){isPrime(20);}
我们对上面的代码稍作分析,就会发现,我们有很多工作是多于的,比如说,我们对一个数a来说,它除以比其1/2还要大的数时,其余数肯定不为0,所以我们可以将代码这么修改:

#include <stdio.h> void isPrime(int number){int j ,i = 1 ;for(j = 2;j <= number;j++){for(i = 2;i <= j /2 ;i++){if(j % i == 0){break;}}if(i > j/2){printf("%d ",j);}}}int main(){isPrime(20);}
需要注意的地方是:for()循环结束的条件,是i<=j/2,和判断是否输出的条件if(i > j/2),这里需要针对4这个数进行修改。虽然将判断的数据缩小了一半,但是这仍然是不够得,在一般的算法题中,这样还是会超时。

(2)下面我们对其再进行优化一下:

现在假设有一个数A,它有除1和本身之外的两个因子,分别称其为m,n即有m*n=A,那么肯定有m<sqrt(A)&&n>sqrt(A)或者m>=sqrt(A)&&n<=sqrt(A)。这里的sqrt(A)代表的是A的平方根。因为一个数的两个因子肯定是在这个数的平方根的两边。所以我们只需要遍历平方根左边的所有数字,如果有一个数字是其因子,那么在其平方根右边,肯定存在一个数也是其因子。所以就有了下面的这个算法:

#include <stdio.h>#include <math.h>void isPrime(int number){int j ,i = 1 ;for(j = 2;j <= number;j++){for(i = 2;i < sqrt(j) ;i++){if(j % i == 0){break;}}if(i > sqrt(j)){printf("%d ",j);}}}int main(){isPrime(20);}

(3)但是当我们处理一个10^5个素数时,这样的算法还是不够快,于是有了下面的这样的神奇算法。

【下面所要说的因子均是除了1和本身之外】【我们给定一个数字范围,比如求20之前的所有素数】我们观察数字2,在此之前没有因子,所以其是素数,输出。---->推导出所有公因子中有2的数则不是素数,于是

a.去掉了4,6,8,10,12,14,16,18,20这些数

接着循环到数字3,发现它并没有被去掉,所以其是素数,输出。接着按照上面的方法,在这个数列中去除因子为3的数,于是

b.去掉了9,15这些数。

接着往下找第一个没有被去除的数,为数字5,所以为素数,输出

……

如此循环直到最后一个数字被处理。得到算法如下:

#include <stdio.h>#include <math.h>void isPrime(int number){int j ,i = 1 ;int array[100];for (i = 0;i<=number;i++){array[i] = i; }for(j = 2;j <= number;j++){//求20之前的素数if(array[j]!=0){printf("%d ",array[j]);}for(i = 2;i <= number ;i++){if( i % j == 0){array[i] = 0;}}}}int main(){isPrime(20);}

运算结果:

总结:在一般的算法题中,使用sqrt()即可满足,但是在对时间要求高一点的情况下,则是使用筛选法没有错的。


0 0
原创粉丝点击