如何判断一个数是不是素数/质数——三种方法超详细总结,包含目前最快方法(附三套完整代码注释)

导入——质数(素数)的定义

质数 :指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
分布规律: 以36N(N+1)为单位,随着N的增大,素数的个数以波浪形式渐渐增多。

1)简单粗暴法

因为质数除了1和本身之外没有其他因数,所以判断n是否为质数,根据定义,直接从2到n-1逐个判断是否存在因数可以将n整除即可。

//完整版方法1 C++代码:
//Zhang Fan
//2019/1226/17:40
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
using namespace std;
int main(){
	int i,n;
	cin>>n;
	for(i=2;i<= n;i++){
		if(n%i==0){		cout<<"no"; system("pause");return 0;}
			else {		cout<<"yes";system("pause");return 0;}
	}//for
}

2)优化开方

上一个方法易于理解,可是效率很显著地低下。
为什么这么说?因为我们在对一个数n进行因数分解时,得到的两个数一定是一个小于等于√n,一个大于等于√n 的。
举个例子 : 6=1×6=2×3 ,√6≈2.45。
这里不是想说6不是质数这个简单的知识,而是 因数2 和 因数3 分布在了√6的两侧。遍历过程从小到大,如果遍历到因数3那么一定遍历过因数2,而在碰到因数2的时候判断就停止了。
所以,上述代码中并不需要遍历到n-1,遍历到 √n 即可。

//完整版方法2 C++代码:
//Zhang Fan
//2019/1226/17:40
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <math.h>
using namespace std;
int main(){
	int n;
	cin>>n;
	float tmp;
	tmp=floor(sqrt((float)n));
     for(int i= 2; i <=tmp; i++){
	        	if(n %i== 0){ cout<<"no";system("pause");
	        			 return 0 ;}
	        }//for
	  //如果能走出for循环,证明n是素数
      cout<<"yes";system("pause");
      return 0 ;
}

3)继续优化

方法2时间复杂度是O(sqrt(n)),已经比方法1的O(n)快了很多。那么还有没有更好的方法呢?
这里要引入一个性质:质数总是等于 6x-1 或者 6x+1,其中 x 是自然数。

证明:令x≥1,将大于等于5的自然数表示如下:
		······ 6x-16x,6x+16x+26x+36x+46x+5,6(x+1),6(x+1)+1 ······
我们从6x开始,逐一进行判断:
	6x		肯定不是质数,是偶数,6x=6*x;
	6x+1	不一定;
	6x+2	肯定不是质数,是偶数,6x+2=2*(3x+1)6x+3	肯定不是质数,6x+3=3*(2x+1)6x+4	肯定不是质数,是偶数,6x+4=2*(3x+2)6x+5	不一定;

所以,质数只可能出现在6x的相邻两侧(但在6的倍数相邻两侧并不是一定就是质数,如 35,所以需要进一步判断)。 ——第一次if判断
既然如此,我们可以以 6 作为阶梯逐步增大到 √n,每次只判断6x-1和6x+1,来遍历所有可能的因数。 ——第二次if判断

完整版方法3 代码:

//完整版方法3 C++代码:
//Zhang Fan
//2019/1226/17:40
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <math.h>
using namespace std;
int main(){	
	int n;
	cin>>n;
		if(n==2 || n==3)	{	cout<<"yes";system("pause");return 0; }
		if(n%6!=1 && n%6!=5){//如果不在6x的左右两侧,直接可以判断不是质数
								cout<<"no";	system("pause");return 0;}
	float n_sqrt;
	n_sqrt=floor(sqrt((float)n));
		for(int i=5;i<=n_sqrt;i+=6){
			if(n%(i)==0 | n%(i+2)==0) {	cout<<"no";
										system("pause");
										return 0;}
			}//for
	//能走到这里证明已经经过了所有检验,是一个合格的质数了
     cout<<"yes";system("pause");return 0; 
}
/*也有写做如下的,一样的想法,都是(左边 = 6x-1,右边 = (6x-1)+ 2)
         for(int i= 5;i <=tmp; i+=6 )
              if(num %i== 0||num %(i+ 2)==0 )
*/

因为每6个数中只需判断2个,理论上讲整体速度应该会是方法2的3倍

注:如有不足欢迎指出,笔者一定虚心思考接受!

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值