c++入门必学算法 质数筛

这篇具有很好参考价值的文章主要介绍了c++入门必学算法 质数筛。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、什么是质数筛

质数筛也叫素数筛,是求1到n之内素数的优化算法,质数筛有两种,埃氏筛和欧拉筛。

埃氏筛的时间复杂度接近O(n*logn),而欧拉筛可以把复杂度降低到O(n),下面看两种算法的到底是如何一步步优化的吧

二、暴力枚举

暴力法求解复杂度O(n)* n \sqrt{n} n ,是新手必学的算法,能解决小数据的素数判断

1、暴力枚举基本思想:

从1到n枚举每一个数,判断每个数是不是素数。质数的定义就是只能被1和自身整除的数字,例如2、3、5、7、11、13…等等,对于每一个数,我们只需要判断这个定义即可

2、模板代码

#include<iostream>
#include<cmath>//需要用到sqrt()函数 
using namespace std;

//判断素数
bool prime(int val){
//     1-3的值需要特判,因为我们循环判断只判断到sqrt(val),1-3是判断不了的
    if(val==1)return 0;
    if(val==2||val==3)return 1;
//     为什么只要判断到sqrt(val)?
//     例如一个数8,它的因数有1、2、4、8,可以发现1<2<sqrt(8)<4<8
//     所以我们只要判断小于sqrt(8)的数就可以了,因为因数都是成对出现的
    for(int i=2;i<=sqrt(val);i++){
//         如果被整除了,那么该数一定不是素数,返回0
        if(val%i==0)return 0;
    }
//     如果是素数就返回1
    return 1;
}

int main(){
    int n;
    cin>>n;
    for(int i=2;i<=n;i++){
//         如果返回值是1,那么该数是素数,输出即可
        if(prime(i)==1){
            cout<<i<<' ';
        }
    }
}

3、运行结果

输入:
100
输出:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

三、埃氏筛

埃氏筛复杂度接近O(n)* log ⁡ n \log n logn,是比较容易理解、容易学习的算法

1、埃氏筛基本思想:

如果一个数是素数,那么它的倍数就不是素数。

例如:
2是素数,那么4、6、8、10、12…都不是素数

3是素数,那么6、9、12、15、18…都不是素数

4不是素数,在2的时候已经知道4不是素数了,我们不必重复说明8、12、16…等等不是素数,因为这些数在2的时候已经可以证明它们不是素数了

5没有被2、3、4标记为它不是素数,那么就说明5不能被2、3、4整除,哪么就说明5是素数

6被在3的时候被标记为不是素数了,直接跳过

7和5一样,没有被2、3、4、5、6标记为不是素数,那么7就是素数,而14、21、28…都不是素数

以上就是埃氏筛的基本思想,我们模拟上面的过程即可快速求出1到n所有的素数

2、模板代码

#include<iostream>
using namespace std;
int main(){
//	  f[i]=1代表i不是素数,f[i]=0代表i是素数 
	int f[100010]={1,1};
    int n;
    cin>>n;
//    埃氏筛 
    for(int i=2;i<=n;i++){
    	if(f[i]==1)continue;
    	for(int j=2;i*j<=n;j++){
    		f[i*j]=1;
		}
    }
//    打印 
    for(int i=0;i<=n;i++){
    	if(f[i]==0){
    		cout<<i<<' ';
		}
	}
}

3、运行结果

输入:
100
输出:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

四、欧拉筛

欧拉筛又叫线性筛,可以把问题时间复杂度优化到O(n)。是求范围内素数最好用的算法

1、对比埃氏筛

埃氏筛的复杂度为什么达不到O(n)呢?因为它在标记不是素数的时候存在大量的重复操作。

例如:
12,它在2、3的时候都被标记了1次
30,它在2、3、5的时候都被标记了1次

欧拉筛的巧妙之处在于它能去掉重复的标记

2、欧拉筛的基本思想

保证每个数只被除1以外最小的质因数标记

例如:
12,它有质因数2、3,那么它只被2标记
15,它有质因数3、5,那么它只被3标记
30,它有质因数2、3、5,那么它只被2标记

实现:
(1) 需要用一个数组 p[n] 把找到的素数存下来

(2) 我们需要逆向思考,从最大的因数找到最小的质因数,例如12,我们通过6,找到质因子2,即当我们处理6的时候需要把12给标记为不是素数

(3)处理一个数时我们遍历每一个已经有的质数,当该质数是该数的因数是退出,因为对于后面的数来说,该数不是最大的因数了!这一步是有点难理解的,慢慢来,多推敲几遍

第三点理解:
例如当前的数是9,那么此时已经找出了质数2、3、5、7
遍历这些质数,那么9*2=18不是质数,9*3=27不是质数,9*5=45不是质数,9*7=63也不是质数,但实际上我们在更新完 27 之后就应该退出了,而不去更新45和63。

因为9并不是45的最大因数,15才是,即这个数在处理15的时候会被标记的,如果现在标记就会出现无用的标记了。

63也是一样的道理,它的最大因数是21,即这个数在处理21的时候会被标记。

为什么处理9的时候,3之后的5、7,最大的因数都不是9?而3和3之前最大因数都是9呢?

我们可以把3当作桥梁,因为3是9的因数,遍历5、7时,9*5可拆分为3*3*5=3*15,9*7可拆分为3*3*7=3*21,而2、3都是不可分的,2*9、3*9,最大的因数就是9,它们的数值应该在此时更新为不是素数

3、模板代码

#include<iostream>
using namespace std;
int main(){
	int d=0;
	int p[100010]={0};
	int f[100010]={1,1};
	int n;
	cin>>n;
	for(int i=2;i<=n;i++){
		if(f[i]==0){//如果没被标记过,那么i是质数 
			p[d++]=i;
		}
		for(int j=0;j<d;j++){
			if(p[j]*i<=n){//标记以i为最大因数的数为不是素数(除了1和本身) 
				f[p[j]*i]=1;
			}else{
				break;
			}
			if(i%p[j]==0){//如果p[j]是i的因数,那么后面的数都不是以i为最大因数的 
				break;
			}
		}
	}
	
	for(int i=0;i<d;i++){//打印1到n的质数 
		cout<<p[i]<<' ';
	}
	
} 

3、运行结果

输入:
100
输出:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

五、总结

埃氏筛的实现原理是比较简单的,使用的场景也比较广泛,但在个别的竞赛题中会卡这点时间,必须使用欧拉筛。

欧拉筛理解的过程是有点难的,但在真正理解之后思路会非常清晰,看不懂就多看两遍

加油咯!兄弟萌文章来源地址https://www.toymoban.com/news/detail-420123.html

到了这里,关于c++入门必学算法 质数筛的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [C语言]输出100以内的所有素数(质数)

    概念解读 : 质数又被称为素数,是指一个大于1的自然数,除了1和它自身外,不能被其它自然数整除,且其个数是无穷的。 思路分析: 对于代码大方向,我们可以直接主函数中写,也可以用可移植性高的自定义函数来写。 100以内样例输出示意 2 3 5 7 11 13 17 19 23 29 31 37 41 43

    2024年02月11日
    浏览(36)
  • C语言素数(质数)判断的三种方法

    本文介绍了判断素数的3种方法,从素数的概念分析,确定找到素数的几个必要条件,设计思路,并将代码进行优化。此外,还使用自定义函数的形式将同样的思路进行实现。 素数,就是仅能被自身和1整除的数字。 首先我们可以提取出判断素数的三个基本条件: 素数是整数

    2024年02月04日
    浏览(35)
  • C语言 五种方法输出100以内的素数(质数) 源码

    目录   写在前面: 输出前20万个素数,对比简单遍历和欧拉筛选的运行时间。 简单遍历: 欧拉筛选: 一、简单遍历 二、遍历至该数的平方根       三、用x/i来代替sqrt(x) 四、朴素筛法 五、埃式筛法 六、欧拉筛法           简单遍历: 3.243秒 欧拉筛选: 0.353秒     

    2024年02月05日
    浏览(28)
  • c++入门必学库函数 memset

    memset是c语言的string.h里的字符串初始化函数,但是也经常用于普通数组的初始化,它的优点就是简单易用,一行代码就可以初始化数据了,当然这完全可以用for循环赋值代替的。 函数模板: memset(数组首地址,初始值,初始化大小) 数组首地址 :数组的首地址是可以直接用数

    2024年02月07日
    浏览(28)
  • C语言:写一个代码,使用 试除法 打印100~200之间的素数(质数)

    使用 试除法 打印100~200之间 的 素数 。                素数(质数) : 一个数 只能被写成 一和本身的积 。 如: 7 只能写成 1*7 ,那就是素数(质数)了。                       =========================================================================                         (一)

    2024年02月08日
    浏览(59)
  • C++算法之旅、08 基础篇 | 质数、约数

    在1的整数中,如果只包含1和本身这两个约数,就被称为质数(素数) 866. 试除法判定质数 - AcWing题库 (O(n)) 约数 d 与 n / d 成对出现 ,可以枚举较小的那一个 (O(sqrt{n})) (d = n/d \\\\ d^2 = n \\\\ d = sqrt{n}) 难点 循环判断条件不要用 sqrt,每次循环都会执行一遍sqrt函数,比较慢 循环

    2024年02月08日
    浏览(35)
  • c++入门必学库函数 next_permutation

    next_permutation的意思是下一个排列,与其相对的是prev_permutation,即上一个排列。我们需要使用全排列的时候就可以直接使用这两个函数,方便又快捷 由于prev_permutation和next_permutation的用法是一样的,下面就值讲解next_permutation的基本用法 next_permutation只能获得上一个排列,如果要

    2024年02月02日
    浏览(24)
  • 【华为OD机考 统一考试机试C卷】素数之积/RSA加密算法(C++ Java JavaScript Python C语言)

    目前在考C卷,经过两个月的收集整理, C卷真题已基本整理完毕 抽到原题的概率为2/3到3/3, 也就是最少抽到两道原题。 请注意:大家刷完C卷真题,最好要把B卷的真题刷一下,因为C卷的部分真题来自B卷。 另外订阅专栏还可以联系笔者开通在线OJ进行刷题,提高刷题效率。

    2024年03月21日
    浏览(37)
  • 【c++笔记】用c++解决一系列质数问题!

            质数是c语言和c++中比较常见的数学问题,本篇文章将带你走进有关质数的一系列基础问题,其中包含常见的思路总结,本篇文章过后,将会持续更新c++算法系列,感兴趣的话麻烦点个关注吧! 希望能给您带来帮助,谢谢您的观看! 目录 题目一:质数口袋 题目二:

    2024年01月21日
    浏览(25)
  • 运用C++查找素数

    查找素数是在学习C/C++中基本的问题,主要是考察对循环的应用,逻辑上并不是很难。 对于常规的素数查找法,解题步骤通常是:(以查找100以内的素数为例) 1.从2开始逐步循环; 2.再进行嵌套循环,判断2能否被2之后的数字整除; 3.如果恰好有能被整除的则结束循环;如果

    2024年02月08日
    浏览(19)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包