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本身就不存在质数的定义中。

这样写是可以判断是否是质数的,但如果你了解过时间复杂度,你就会喊出:我的老天爷啊!这也太慢了!

\[判断一个质数的时间复杂度高达了:O(N) \]

如何更加快速地判断一个数是否是质数?

这里我们要引入一个显而易见的论据。

如果一个数n能被d整除(或者说d整除n),那么n也一定能被n/d整除

我们用数学符号表示:

\[d|n\Rightarrow \frac{n}{d}|n \]

|是整除符号,表示右边的数可以被左边的数整除

我们举个例子理解吧:

\[3|18 \Rightarrow \frac{18}{3}|18 \]

3可以整除18,18/3也可以整除18,这是显而易见的

因为如果存在一个大于1的自然数,它就一定能写成如下的形式:

\[N=A*B \]

哪怕是质数,也可以写成1*本身 的形式,如果它是个合数,那么A和B必定不是1和本身。

那么从这个显而易见的结论,我们可以推出另一个结论:

一个大于1的合数,它的因子除了1和本身以外,总是成对出现的,不过这一对可能是一样的数,比如36=6*6。

由于合数中的因子是成对出现的,那么我们只要枚举成对出现中那个较小的那个数,就可以判断它是否是合数了。又因为一个大于1的数不是合数就是质数,所以就可以反向判断质数了

设n为一个大于1的正整数,设d是n成对因子中较小的那一个

\[d \leq \frac{n}{d} \Leftrightarrow d \leq \sqrt{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;
}

\[时间复杂度从O(N) \Rightarrow O(\sqrt{N}) \]

这样子我们可以在根号n的速度下判断一个数是否是质数了。

posted @ 2020-07-26 15:33  程序员郭半仙  阅读(390)  评论(0)    收藏  举报