ACM数论01-素数(质数)的判断
用代码判断素数(质数)
素数,又名质数。它的定义很简单:
在大于1的自然数中,只有1和它本身两个因子的数,就是素数(质数)。
注:本人喜欢用质数这个名字,所以下文中都用质数代表素数
质数的名字叫prime number
,所以在代码中,我们对质数总是使用prime进行变量的命名,对质数判断的函数也会变成isprime()
(是质数吗?)或者干脆用简写isp()
根据定义,我们可以很轻松的写出判断一个质数的代码:
(c++):
bool isp(int n)
{
for(int i = 2; i < n; i++)
{
if(n % i == 0) return false;
}
return true;
}
(java):
static boolean isp(int n)
{
for(int i = 2; i < n; i++)
{
if(n % i == 0) return false;
}
return true;
}
这里默认不考虑1到底是不是质数,因为1本身就不存在质数的定义中。
这样写是可以判断是否是质数的,但如果你了解过时间复杂度,你就会喊出:我的老天爷啊!这也太慢了!
如何更加快速地判断一个数是否是质数?
这里我们要引入一个显而易见的论据。
如果一个数n能被d整除(或者说d整除n),那么n也一定能被n/d整除
我们用数学符号表示:
|
是整除符号,表示右边的数可以被左边的数整除
我们举个例子理解吧:
3可以整除18,18/3也可以整除18,这是显而易见的
。
因为如果存在一个大于1的自然数,它就一定能写成如下的形式:
哪怕是质数,也可以写成1*本身
的形式,如果它是个合数,那么A和B必定不是1和本身。
那么从这个显而易见的结论,我们可以推出另一个结论:
一个大于1的合数,它的因子除了1和本身以外,总是成对出现的,不过这一对可能是一样的数,比如36=6*6。
由于合数中的因子是成对出现的,那么我们只要枚举成对出现中那个较小的那个数,就可以判断它是否是合数了。又因为一个大于1的数不是合数就是质数,所以就可以反向判断质数了
设n为一个大于1的正整数,设d是n成对因子中较小的那一个
所以通过证明以后我们可以发现,只要枚举小于等于根号n的所有正整数,就可以判断一个数是否是质数了,但是由于在编程语言中,sqrt的运算速度很慢,所以我们使用的是d < n / d这样的写法
(c++):
bool isp(int n)
{
//写 for(int i = 2; i <= sqrt(n); i++) 太慢
for(int i = 2; i <= n / i; i++)
{
if(n % i == 0) return false;
}
return true;
}
(java):
static boolean isp(int n)
{
for(int i = 2; i <= n / i; i++)
{
if(n % i == 0) return false;
}
return true;
}
这样子我们可以在根号n的速度下判断一个数是否是质数了。