码迷,mamicode.com
首页 > 其他好文 > 详细

质数及其判法

时间:2020-02-19 13:08:46      阅读:75      评论:0      收藏:0      [点我收藏+]

标签:分解   logs   遍历   pre   退出   ret   思路   内联函数   code   

目录

目录地址

什么是质数

数学家们希望用乘法表示所有的正整数

这时候,他们发现,有一些数字(假定为 \(p\) ),它们只能用 \(1\times p\) 的形式表示(不考虑负因数),其它不能写成任何别的形式

对于这种数字,他们称呼为 质数 ,或称呼为 素数

而换句话说,它们只能分解为 \(1\) 乘上它本身;也就是说,它的因数只有 \(1\) 与它本身

这就是质数最重要的性质,也是它的定义

而对于其它的数字,我们称呼为 合数

合数的一些性质我们将会在后面的贴子中提到


质数的判法

对于一个数字 \(n\) 我们如何判定它是不是质数呢?

根据定义,我们很容易想到:枚举数字,查询是否只有 \(1\)\(n\) 是它的因数

而如果数字 \(m\) 是数字 \(n\) 的因数,很显然,存在数字 \(k\) 使得 \(k\times m=n\)

反过来,我们可以写作 \(n\div m=k\cdots0\)

也就是说,如果 \(m\) 是数字 \(n\) 的因数, \(n\) 除以 \(m\) 的因数一定为 \(0\)

既然质数的因数只有 \(1\) 与它本身,那么其他数字除完的因数就一定不能为 \(0\)

根据数字的因数一定小于等于它本身,我们很快就可以写出程序(以 C++ 为例)

bool isprime=1;
for(int i=1;i<=n;i++){
    if(n%i==0&&i!=1&&i!=n){
        isprime=0;
    }
}

当然,其实我们这样做的话,直接遍历的范围改成 \(2\)~\((n-1)\) 就行了

bool isprime=1;
for(int i=2;i<=n-1;i++){
    if(n%i==0){
        isprime=0;
    }
}

这样一来,时间复杂度是 \(O(n)\)


优化

时间复杂度能更快吗?

可以的

我们现在的思路是:枚举数字,查看 \(n\) 是否是合数

但我们想想,如果 \(n\) 是合数,那么它一定能写成 \(n=m\times k(m,k\neq 1,n)\) 的形式

我们直接假定 \(m\leq k\)

那么,显然 \(m\leq \sqrt{n}\)

这一步的证明我们可以用反证法:

\(m>\sqrt{n}\) , 则 \(k\times m\geq m\times m=m^2>(\sqrt{n})^2=n\) 就不是 \(n\)

所以 \(m\leq sqrt{n}\)

我们可以利用这个来优化我们的代码:我们修改上界,搜到 \(\sqrt n\) 即可

bool isprime=1;
for(int i=2;i<=sqrt(n);i++){
    if(n%i==0){
        isprime=0;
    }
}

当然,能不用 sqrt 函数我们尽量就不要用,毕竟它还需要支持实数的运算,跑得并不快

我们用 i*i<=n 来代替 i<=sqrt(n) 可以降低常数

bool isprime=1;
for(int i=2;i*i<=n;i++){
    if(n%i==0){
        isprime=0;
    }
}

复杂度 \(O(\sqrt n)\)

当然,想优化常数还能再优化:判定完不是质数就可以直接退出了

bool isprime=1;
for(int i=2;i*i<=n;i++){
    if(n%i==0){
        isprime=0;
        break;
    }
}

或者我们搞成内联函数的形式:

inline bool isprime(int n){
    for(int i=2;i*i<=n;i++) if(n%i==0) return 0;
    return 1;
}

这样就完成了

质数及其判法

标签:分解   logs   遍历   pre   退出   ret   思路   内联函数   code   

原文地址:https://www.cnblogs.com/JustinRochester/p/12330611.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!