当前位置:首页 > C++知识 > 正文内容

质数(素数)的判断

亿万年的星光3年前 (2021-10-04)C++知识1277


一、定义法

// 1 定义法(除了1和他本身之外,没有任何一个数能被整除)(试除法)
bool is_prime3(unsigned long long n) { //slow
    for (int i = 2; i < n - 1; i++) {
        if (n % i == 0) {
            return 0;
        }
    }
    return 1;
}

二、定义法的改进

/*
根据如果一个数是合数,那么它的最小质因数肯定小于等于它的平方根。
用反证法可以证明一下。假设x是n的最小质因数,则存在n/x=p。p>x,x*p=n。如果x不小于等于它的平方根,则x*x>n,而p>x,故x*p>n,假设不成立。合数是与质数相对应的自然数。一个大于1的自然数如果它不是合数,则它是质数。也就是说如果一个数能被它的最小质因数整除的话,那它肯定是合数,即不是质数。所以判断一个数是否是质数,只需判断它是否能被小于它开跟号后的所有数整除,因此,这样做的运算少了很多,降低了时间复杂度。
*/
int isprime(int m)
{
    int i;
    for(i=2;i<=sqrt(m);i++)    /*sqrt(int n)这个函数需要引入math.h头文件*/
      if(m%i==0)
        return 0;
    return 1;
}

三、查表法

把一定范围内的素数都求出来直接复制到数组中,然后查询即可


四、孪生素数

/*
孪生素数: 所谓孪生素数指的是间隔为 2 的相邻素数,它们之间的距离已经近得不能再近了。
若n≥6且n-1和n+1为孪生素数,那么n一定是6的倍数。
证明:
∵ n-1和n+1是素数 ┈┈┈┈┈ ①
∴ n-1和n+1是奇数
∴ n是偶数,即n是2的倍数 ┈┈┈┈┈ ②
假设n不是3的倍数,得:
n=3x+1 或 n=3x+2,
如果n=3x+1,则n-1=3x,与①违背,故n≠3x+1;
如果n=3x+2,则n+1=3(x+1),与①违背,故n≠3x+2;
∴假设不成立,即n是3的倍数,又有②得结论:
n是6的倍数。
 
由上面的规律可以推出下面结论:
若x≧1且n=6x-1或n=6x+1不是素数,那么n一定不是2和3的倍数。
证明:
∵n=6x-1或n=6x+1,即n=2(3x)-1或n=2(3x)+1或n=3(2x)-1或n=3(2x)+1。
∴n一定不是2和3的倍数。
 
素数出现规律:
当n≧5时,如果n为素数,那么n mod 6 = 1 或 n mod 6 = 5,即n一定出现在6x(x≥1)两侧。
证明:
当x≥1时,有如下表示方法:
┈┈ 6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1┈┈
不在6x两侧的数为6x+2,6x+3,6x+4,即2(3x+1),3(2x+1),2(3x+2),它们一定不是素数,所以素数一定出现在6x的两侧。
*/
bool isPrime(int num)
{
    if (num == 2 || num == 3)
        return true;
    if (num % 6 != 1 && num % 6 != 5)
        return false;
    for (int i = 5; i*i <= num; i += 6)
        if (num % i == 0 || num % (i+2) == 0)
            return false;
    return true;
}

五、埃式筛法

首先,将2到n范围内的所有整数写下来。其中最小的数字2是素数。将表中所有2的倍数都划去。表中剩余的最小数字是3,它不能被更小的数整除,所以是素数。再将表中所有3的倍数全都划去。
依次类推,如果表中剩余的最小数字是m时,m就是素数。然后将表中所有m的倍数全部划去。像这样反复操作,就能依次枚举n以内的素数。

#include<iostream>
using namespace std;
int main() {
	int i,j,n,flag=1;
	bool a[100]= {0};
	for(i=1; i<=100; i++) {
		for(j=2; j<=100; j++) {
			a[i*j]=1;
		}
	}
	for(int p=0; p<=100; p++)
		if(a[p]==0) {
			cout<<a[p]<<" ";
		}
	return 0;
}


六、线性筛法(欧拉筛)

// 由于埃筛法做了许多不必要的循环,所以欧拉筛在埃筛法的基础上,省去了一些步骤,时间复杂度O(n)
int primes(int n)
{
	st[1] = true;
	for(int i=2;i<=n;i++)
	{
		if(!st[i])prime[++k] = i;
		
		for(int j=1;prime[j]<=n/i;j++)
		{
			st[prime[j] * i] = true;
			if(i % prime[j] == 0)break;
		}
	}
	return k; 
}


扫描二维码推送至手机访问。

版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

分享给朋友:

相关文章

【入门篇】C++ 中变量的简单使用

【入门篇】C++ 中变量的简单使用

1.什么是变量”变量“通俗来讲就是能变的量。在程序设计中,变量是一个个不同类型的盒子,当盒子里装了苹果时,盒子就代表苹果,当然,我们需要给一个个盒子起不同的名字。像下面的图片一样,一个盒子,给他取一个...

【算法】单链表的一些操作(存取、查找、取出、插入、删除)

一、单链表结构的建立与输出#include<iostream> using namespace std; struct Node{ int ...

【数据结构】栈—括号匹配检验

【数据结构】栈—括号匹配检验

【题目描述】假设表达式中允许包含两种括号:圆括号和方括号,其嵌套的顺序随意,如([ ]())或[  (  [  ] [  ] ) ] 等为正确的匹配,[&nbs...

树的遍历

在应用树结构解决问题时,往往要求按照某种此项获得树中全部结点的信息,这种操作叫做树的遍历。遍历的方法有很多种。常用的有:A. 先序遍历:先访问根结点,再从左到右按照先序思想遍历各子树。B. 后序遍历:...

指针(三):指针与函数

1.交换的例子#include<iostream> #include<cstdio> #include<cstring> using namespa...

【题解】围圈报数(约瑟夫问题)

【题解】围圈报数(约瑟夫问题)

【题目描述】有n个人依次围成一圈,从第1个人开始报数,数到第m个人出列,然后从出列的下一个人开始报数,数到第m个热呢又出列,... ,如此反复到所有的人全部出列为止。设n个人的编号分别为1,2,......