对于素数字,大家都很熟悉了。凡是学习编程的都写过判断素数的程序。我们从最简单的开始,依次深入。
首先是教科书中的方法,这种方法的思路比较简单,给定一个数num,从2--(num-1),一直实验,若其中某个数字能被num整除,说明num不是素数,返回false,反之,则这个数是素数。很简单的方法,符合素数的基本定义,代码清单如下:
bool prime(int num)
{
if (num < 2)
return false;
for (int i = 2; i < num; i++)
if (num % i == 0)
return false;
return true;
}
上面的代码是最原始的判断一个数是否为素数的方法,但是效率不是很好,原因就在于那个for循环中。其实,在判断的时候没有必要达到(num-1)到达num/2,甚至sqrt(num)就已经足够了(离散数学),所以就有了改进的版本,代码清单如下:
bool prime(int num)
{
if (num < 2)
return 0;
int temp = sqrt (num);
for (int i = 2; i <= temp; i++)
if (num % i == 0)
return false;
return true;
}
这个程序的要点在于,一定要取到sqrt(num),也就是说要用“<=”,而不是“<”。好了,教科书上的改进方法到此为止,实际上,对于用这个思路判断素数来说的众多方法,这个已经可以看做是比较好的了。当然,其实还是可以改进的,比如说,对于除了2以外的偶数,都不可能为素数,所以可以先判断是否可以整除2,如果可以,返回false,反之在进行下一步判断。如果是非偶数,那么在for里面的迭代也就没有必要++了,直接+=2也是可以的,当然,要把初始变量i=2改成i=3,于是,程序就成了下面这个样子:
bool prime(int num)
{
if (num == 2)
return true;
if ( num % 2 == 0 || num < 2)//其实num%2是省去了对一个数字开方的运算
return false;
int temp = sqrt (num);
for (int i = 3; i <= temp; i+=2)
if (num % i == 0)
return false;
return true;
}
对于程序中的num<2,其实并不是想对负数也进行判断,它对应的特殊情况是num=0,或者num=1的情况。教科书的方法,也就是说,大部分的本科生用这样的方法判断一个数是否为素数,但是对于这个方法来说,还是那句老话,时间效率不是很好,O(n^2),在进行ACM的时候,某些情况下是不能满足要求,于是有了更好的筛法。
ACM中常用的方法是筛法,因为时间效率差不多O(n)吧。它需要借助一个辅助的数组,数组的下标代表待判断的数字,记录的信息代表这个数是否为素数,这就是常说的空间换时间吧。多说是废话,直接代码:
int rem[10000]={1,1};//0和1不是素数,置为1,其余的都置为0
void prime()
{
int temp = sqrt (10000);
for (int i = 2 ; i <= temp ; i++)
if ( !rem[ i ] )
for (int j = i + i ; j <= 10000 ; j += i)
rem[ j ] = 1;
}
函数结束后,从1---10000,是素数的位都是0,不是的都是1,用的时候只要看是0还是1,就可以了。程序里的10000是数字可能出现的最大值。ACM的另一种常用的方法就是,把给定范围的素数先全部算出来保存到数组里,就像这个样子prim[10]={2,3,5,7,11},用的时候看里面有没有,当然,计算的过程是省略的,数组内的东西全部是事先已经算好了手工写到数组里面的,毕竟这样子查找更快。
到这里,可以发现,教科书的方法适用于对某个数字的判断,而ACM常用方法更适合在某个数字区间范围内大量的重复判断。
本来,应该到这里就结束的,但是上午的时候看到一个老外的求解素数的方法,感觉思路很有意思,就一并写进来。
perl -lne ' (1x$_) =~ ^1?$ | ^(11+?)\1+$ || print "$_ is a prime" ',输出结果如下:
1
2
2 is a prime
3
3 is a prime
4
5
5 is a prime
6
7
7 is a prime....
核心部分为“ ^1?$ | ^(11+?)\1+$”。用到的正是筛法的思想,看看待判断数字是不是某个数字的倍数(通过判断1的个数)。很巧妙的正则表达式的解决素数的方法。有兴趣的同学可以访问http://www.catonmat.net/blog/perl-regex-that-matches-prime-numbers/看看英文解释,比较好懂。
希望这篇文章能够对你有所帮助。