转载自:http://blog.csdn.net/ylyg050518/article/details/48266999
继续算法之旅。关于素数判定这个问题,也是一个很经典的程序设计题目。
概念:质数(prime number)又称素数,有无限个。一个大于1的自然数,除了1和它本身外,不能被其他自然数整除,换句话说就是该数除了1和它本身以外不再有其他的因数,否则称为合数。
朴素法
分析:如果要判定一个数自然数n(n>1)是不是素数,从素数定义出发,首先想到的肯定是采用循环,遍历 2至n-1所有值,逐个与n除,判定是否可以整除,如果存在能够整除的情况,则n不为素数。
改进方法:脱离单纯程序实现的角度,你会发现可以改进的地方在于遍历的范围,如果略作思考,你会发现n/2到n-1的值是不用遍历的,因为最小的试探除数是2,大于n/2的数肯定不能被整除。进一步思考,遍历的范围还可以继续缩小,其实只需将遍历的上限设置成n的平方根即可。简单分析,假设 n可以被p整除,结果为q ,即q=n/p,如果p大于n的平方根,q必定小于n的平方根,所以只要测试n的平方根以下的数字即可,这样可以进一步提高运算效率。
以下是代码:
筛数法
筛数法求素数的基本思想是:把从1开始的、某一范围内的正整数从小到大顺序排列, 1不是素数,首先把它筛掉。剩下的数中选择最小的数是素数,然后去掉它的倍数。依次类推,直到筛子为空时结束。
具体做法如下:
<1> 先将1挖掉(因为1不是素数)。
<2> 用2去除它后面的各个数,把能被2整除的数挖掉,即把2的倍数挖掉。
<3> 用3去除它后面的各数,把3的倍数挖掉。
<4> 分别用4、5…各数作为除数去除这些数以后的各数。(事实上,可以简化,如果需要找1~n范围内素数表,只需进行到除数为n^2(根号n),取其整数即可。例如对1~50,只需进行到将50^2作为除数即可。)
如上算法可表示为:
<1> 挖去1;
<2> 用刚才被挖去的数的下一个数p去除p后面各数,把p的倍数挖掉;
<3> 检查p是否小于n^2的整数部分(如果n=1000, 则检查p<31?),如果是,则返回(2)继续执行,否则就结束;
<4> 纸上剩下的数就是素数。
特别说明:为什么除数的筛选范围只到问题规模N的平方根即可?因为通过分析可以知道,当除数的范围大于这个上限(N的平方根取整)时,所有的要筛选的值都和之前筛选过的重复,继续筛选无效。
6N±1法求素数
任何一个自然数,总可以表示成为如下的形式之一:
6N,6N+1,6N+2,6N+3,6N+4,6N+5 (N=0,1,2,…)
显然,当N≥1时,6N,6N+2,6N+3,6N+4都不是素数,只有形如6N+1和6N+5的自然数有可能是素数。所以,除了2和3之外,所有的素数都可以表示成6N±1的形式(N为自然数)。根据上述分析,我们只对形如6 N±1的自然数进行筛选,这样就可以大大减少筛选的次数,从而进一步提高程序的运行效率和速度。
实现思路:可以和朴素法判定单个自然数是否为素数结合起来,利用循环递增获取指定范围具备6 N±1特征的数字,利用朴素法来判定数字是否为素数,打印出结果。
以下是代码
特别说明:以上只给出代码样例,并不能保证代码的权威性,加之作者水平有限,难免有不足之处,还望大家多多包涵。