【算法】素数(质数)判断方法「建议收藏」

【算法】素数(质数)判断方法「建议收藏」素数(质数)的判断在算法问题中经常遇到,这里小结几种常用的判断方法。首先,我们来看一下素数(质数)的定义:质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数。我们可以从它的定义得到判断素数的第一个方法:从2到n-1,判断是否存在能被n整除的数,既(n%i==0,2<=i<=n-1),如果有就不是素数,否则为素数。(这里为了比

大家好,又见面了,我是你们的朋友全栈君。

注:本篇文章已搬至个人博客中, 点击前往

素数(质数)的判断在算法问题中经常遇到,这里小结几种常用的判断方法。

素数(质数)的定义

首先,我们来看一下素数(质数)的定义:质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数。

方法一

我们可以从它的定义得到判断素数的 第一个方法: 2 2 2 n − 1 n – 1 n1, 判断是否存在能被n整除的数,既 ( n % i = = 0 , 2 < = i < = n − 1 ) (n \% i == 0, 2 <= i <= n – 1) (n%i==0,2<=i<=n1),如果有就不是素数,否则为素数。

(这里为了比较几种算法的性能,用计算出1000,000中有多少个素数所需的时间作为性能比较的参考。附上本篇博文所有程序的运行环境(机房哈哈):系统windows xp, cpu:E5200,2.50GHZ, 0.99GB内存,IDE:codeblocks)

首先,可以先作一个小的优化,既除2以外,只需判断所有的奇数是否是素数。

//素数判断方法1
#include<stdio.h>
#include<time.h>
#define Max 1000000
int main()
{ 
   
    int sum = 1;//2单独处理,sum为素数的个数
    for(int i = 3; i <= Max; i+=2)
    { 
   //因为偶数除了2之外都不是素数(质数),所以只需判断奇数,从3开始每次+2
        int j;
        for(j = 2; j < i; j++)//判断
            if(i%j == 0)break;
        if(j == i)
            sum++;
    }
    printf("Time used = %0.2f s\n",(double)clock()/CLOCKS_PER_SEC);//获取程序运行的时间
    printf("%d",sum);
    return 0;
}

程序的时间复杂度为O( n 2 n^2 n2)。
运行结果
这里写图片描述
结果表明n的数量级太大时,不宜采用该方法。
同时也可以得到结论 1000 , 000 1000,000 1000,000中有 78498 78498 78498个素数。

接下来的方法其实都是对上述方法进行优化,可以很好地降低时间复杂度。
利用以下结论:对正整数 n n n,如果用2到 n \sqrt{n} n
之间的所有整数去除,均无法整除,则 n n n为质数。

方法二

//素数判断方法2
#include<stdio.h>
#include<time.h>
#include<math.h>
#define Max 1000000
int main()
{ 
   
    int sum = 1;
    for(int i = 3; i <= Max; i+=2)
    { 
   //因为偶数除了2之外都不是素数(质数),所以只需判断奇数,从3开始每次+2
        int j;
        for(j = 2; j <= (int)sqrt(i); j++)//利用上述结论判断
            if(i%j == 0)break;
        if(j > (int)sqrt(i))
            sum++;
    }
    printf("Time used = %0.2f s\n",(double)clock()/CLOCKS_PER_SEC);
    printf("%d",sum);
    return 0;
}

程序的时间复杂度为O( n \sqrt{n} n
)。
运行结果
这里写图片描述
可以看到程序的运行时间已经大幅度地降低。

接下来的方法需要利用到孪生素数的一些特点和结论。

孪生素数

孪生素数:孪生素数指的是间隔为 2 2 2 的相邻素数。
1.当 n > = 6 n >= 6 n>=6, n − 1 n – 1 n1 n + 1 n + 1 n+1 为孪生素数,那么n 一定是6的倍数。
Proof :

∵ n − 1 , n + 1 是 素 数 , 也 即 n − 1 和 n + 1 是 奇 数 ∴ n 是 偶 数 , n 是 2 的 倍 数 。 设 n 不 是 3 的 倍 数 , 即 n = 3 k + 1 或 n = 3 k + 2 。 ( i ) 当 n = 3 k + 1 时 , 那 么 n − 1 = 3 k , 已 经 与 n − 1 是 素 数 矛 盾 。 ( i i ) 当 n = 3 k + 2 时 , 那 么 n + 1 = 3 ( k + 1 ) , 已 经 与 n + 1 是 素 数 矛 盾 。 综 上 所 述 , n 是 3 的 倍 数 。 ∵ n 既 是 2 的 倍 数 , 又 是 3 的 倍 数 ∴ n 是 6 的 倍 数 。 \begin{aligned} &∵ n – 1, n + 1是素数,也即 n – 1 和 n + 1是 奇数\\ &∴n 是 偶数,n 是 2 的倍数。\\ &设 n 不是 3 的倍数,即 n = 3k + 1 或 n = 3k + 2。\\ &(i)当 n = 3k + 1 时,那么 n – 1 = 3k,已经与 n – 1 是素数矛盾。\\ &(ii)当 n = 3k + 2 时, 那么 n +1=3(k + 1),已经与 n + 1是素数矛盾。\\ &综上所述,n 是 3 的倍数。\\ &∵n既是2的倍数,又是3的倍数\\ &∴n 是6的倍数。\\ \end{aligned} n1,n+1n1n+1nn2n3n=3k+1n=3k+2(i)n=3k+1n1=3k,n1(ii)n=3k+2n+3(k+1),n+1n3n23n6

推论1 : x > = 1 x >= 1 x>=1, ( 6 x − 1 ) (6x – 1) (6x1) ( 6 x + 1 ) (6x + 1) (6x+1)不是素数时,它们的质因子不包括2和3的倍数,因为 2 ( 3 x ) − 1 , 3 ( 2 x ) − 1 , 2 ( 3 x ) + 1 , 3 ( 2 x ) + 1 2(3x) – 1, 3(2x) – 1,2(3x) + 1, 3(2x) + 1 2(3x)1,3(2x)1,2(3x)+1,3(2x)+1

2.素数的分布规律:当 n > = 5 n >= 5 n>=5时,如果n为素数,那么 n % 6 = 1 ∣ ∣ n % 6 = 5 n \% 6 = 1 || n \% 6 = 5 n%6=1n%6=5,即n一定出现在 6 x ( x ≥ 1 ) 6x(x≥1) 6x(x1)两侧。(就是说大于等于5的素数一定是分布在6倍数的左右两侧,但在6倍数左右两侧的数不一定是素数)
Proof:
可 以 把 6 x 附 近 的 数 用 以 下 方 式 表 示 : … … ( 6 x − 1 ) , 6 x , 6 x + 1 , 2 ( 3 x + 1 ) , 3 ( 2 x + 1 ) , 2 ( 3 x + 2 ) , 6 x + 5 , 6 ( x + 1 ) … … 不 在 6 x 两 侧 的 数 为 : 2 ( 3 x + 1 ) , 3 ( 2 x + 1 ) , 2 ( 3 x + 2 ) , 它 们 不 是 素 数 , 所 以 素 数 出 现 在 6 x 的 两 侧 。 \begin{aligned} &可以把6x附近的数用以下方式表示:\\ &……(6x – 1), 6x, 6x+1, 2(3x+1), 3(2x+1), 2(3x +2), 6x + 5, 6(x+1)……\\ &不在6x两侧的数为: 2(3x+1), 3(2x+1), 2(3x +2),它们不是素数,所以素数出现在6x的两侧。\\ \end{aligned} 6x(6x1),6x,6x+1,2(3x+1),3(2x+1),2(3x+2),6x+5,6(x+1)6x2(3x+1),3(2x+1),2(3x+2),6x
  有了以上的理论基础,我们可以对方法2进一步地优化,首先不在 6 x 6x 6x左右的数 2 , 3 2,3 2,3单独处理,接下来只要判断 6 x 6x 6x两侧的数是否为素数。因为合数总是可以写成素数的乘积,那么我们直接用n去除以质数就可以达到很好地优化目的。而质数一定是 6 x 6x 6x 两侧的数(推论一已证明了当 n > = 5 n >= 5 n>=5时,n不是素数时,n 不含质因子2,3) , 6 x 6x 6x 两侧的数是大于素数的集合,因此可以用 n n n 除以 6 x 6x 6x 两侧的数即if(n % i == 0 || n % (i + 2) == 0)时,不是素数。

方法三:基于孪生素数方法筛除

//素数判断方法3
#include<stdio.h>
#include<time.h>
#include<math.h>
#define Max 1000000
using namespace std;
int main()
{ 
   
    int sum = 1;//已经将2单独处理
    int flag = 0;
    for(int i = 3; i <= Max; i+=2)
    { 
   
        if(i == 3)//3单独处理
            sum++;
         
        if(i % 6 != 1 && i % 6 !=5)
            continue;//不是6x两侧的数不是素数
        
        for(int j = 5; j <= (int)sqrt(i); j+=6)//对6x两侧的数进行判断
            if(i%j == 0 || i%(j + 2) ==0)
            { 
   
                flag = 1;
                break;
            }
            if(flag == 1)
            { 
   
                flag = 0;
                continue;
            }
        sum++;
    }
    printf("Time used = %0.2f s\n",(double)clock()/CLOCKS_PER_SEC);
    printf("%d",sum);
    return 0;
}

运行结果:
【算法】素数(质数)判断方法「建议收藏」
方法3运行结果表明比方法2快速了许多倍,已经是很高效的算法了。

方法四:普通筛选法

更新日记:2018/1/31增加普通筛选法
比上面几种方法更快,也比较容易理解。
思想: 一个素数的倍数都不是素数。
时间复杂度: O(nloglogn)

#include<iostream>
#include<vector>
using namespace std;
const int maxt = 1000000;
vector<bool>prime;
int main()
{ 
   
	prime.resize(maxt,1);
	prime[0] = prime[1] = 0;//1是素数,0是非素数
	for(int i = 2; i*i <= prime.size(); i++)
	{ 
   
		if(prime[i] == 1)
		for(int j = i*2; j <= prime.size(); j += i)
		{ 
   
			prime[j] =  0;
		}
	}
	return 0;
}

相关习题:蓝桥杯 Torry的困惑(基本型)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/150307.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(1)


相关推荐

  • 怎么判断Long类型为空_java将list转为string

    怎么判断Long类型为空_java将list转为stringList<String>和List<Long>类型相互转化 jdk 8.0 新特性

  • 彻底搞懂0-1背包问题(动态规划)

    彻底搞懂0-1背包问题(动态规划)看了很多网上的博客,发现对于0-1背包问题很多讲的都很专业,初学者学起来还是比较吃力,今天我就用最简单最形象的语言来描述一下0-1背包问题,为什么不能用贪婪算法,而要选择使用动态规划。首先对于0-1背包问题,我们需要知道的是:每一个物品只有1个,要么全拿,要么不拿,最后使得拿到的物品的总价值最大。假如一个小偷有一个可以容纳4千克的背包,但是发现面前只有有3样物品可以偷:台灯(30元,4千克)、音响(20元,3千克)、充电宝(15元,1千克)(价格和重量可能有点奇怪????)。问,小偷能够偷到的物品的

  • webstorm 2021激活码【永久激活】

    (webstorm 2021激活码)最近有小伙伴私信我,问我这边有没有免费的intellijIdea的激活码,然后我将全栈君台教程分享给他了。激活成功之后他一直表示感谢,哈哈~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.htmlML…

  • php 中使用cURL发送get/post请求,上传图片,批处理

    php 中使用cURL发送get/post请求,上传图片,批处理

    2021年10月29日
  • 黑苹果安装教程OC引导「建议收藏」

    黑苹果安装教程OC引导「建议收藏」小白安装指南1.从零开始,自制EFI,安装黑苹果2.网络下载EFI(80%可能你根本找不到能用的)3.黑苹果安装过程卡代码4.安装好黑苹果后引导修复5.修改BIOS5.其他可能有帮助的链接首先声明,我也是小白,只是总结一下我安装黑苹果过程中参考过的教程。以下内容如有帮助本人深感欣慰。最开始装黑苹果心里特别没底,不知从何下手,那先看1.从零开始,自制EFI,安装黑苹果推荐从零学习,大约需要5个小时自己就能安装黑苹果了。1.视频中使用的是OC0.6.5版本,现在已经升级到0.6.6但是并没有什么区

  • share topology_search索引器

    share topology_search索引器如果你知道如何在Rapidshare上搜索的话它就是一个金矿。这里有两个基本方法可以进行搜索,一是使用Google搜索参数对Rapidshare进行搜索,一些网站提供一个基本搜索界面但不如你自己添加参数进行搜索要好。还有一种网站提供自己的搜索数据库进行搜索。第二种网站的搜索更广泛,因为他们使用不同的来源去发现Rapidshare上的新文件包括用户上传的。我不喜欢第一种网站来搜索Rapidshar…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号