当前位置: 首页 > news >正文

素数筛-试除法 埃氏筛 线性筛

✨✨ 欢迎大家来到小伞的大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:算法
小伞的主页:xiaosan_blog

gitee:许星让 (xu-xingrang) - Gitee.com

制作不易!点个赞吧!!谢谢喵!!

定义:

质数(素数)是指在大于 1 的**自然数**中,除了 1 和它本身以外不再有其他因数的自然数。

根据素数这一定义,可以提炼出几点内容

  1. 素数是自然数,因此是整数
  2. 素数是大于1的自然数,因此小于等于1的数字都不是素数(包括负数,0和小数)
  3. 素数只有两个因数,1和自身
  4. 结合1,2,3点,可以推断出,在自然数范围内,最小的素数是2

1.试除法

这应该是最容易想到的,我们只需要在[ 2,sqrt[n] ]范围内找到一个数,逐一枚举数字,对每一素数,尝试用n去除。

  • 如果可以被整除,则说明枚举的数字是n的因子。根据素数定义,数字n非素数
  • 如果不可以被整除,则需要继续往后枚举,查看其他枚举数字相除之后的结果
    • 如果后面有可以被整除的数字,则结果和上面第一条一样。
    • 如果在[ 2,sqrt[n] ]范围内都没有可以被整除的数字,则说明数字n在[1,n]范围内只有1和n两个因子,因此n是素数。
#define n 10010 vector<bool> isPrime(n + 1, true);//标记i位置是否为素数 void init_prime() { for (int i = 0; i < n; ++i) { if (i <= 1) isPrime[i] = false; else for (int j = 2; j <= sqrt(i); ++j) { //小于等于sqrt(i)的位置,当sqrt(i)<=j<n时,其中i%j只会在(0,1)中,所以减去多于的枚举 if (i % j == 0) { isPrime[i] = false; break; } } } }

如果只对于一个数是否为素数,其中的On(sqrt(n));

1.1 剪枝

我们发现素数一定是除了2以外的奇数

#define n 10010 vector<bool> isPrime(n + 1, true);//标记i位置是否为素数 void init_prime() { for (int i = 0; i < n; ++i) { if (i <= 1) isPrime[i] = false; else if (i != 2 && i % 2 == 0) { isPrime[i] = false; } else { for (int j = 2; j <= sqrt(i); ++j) { //小于等于sqrt(i)的位置,当sqrt(i)<=j<n时,其中i%j只会在(0,1)中,所以减去多于的枚举 if (i % j == 0) { isPrime[i] = false; break; } } } } }

2. 素数筛-埃氏筛(埃拉托斯特尼筛法)

一般用于对一整块的区间进行标记,用于判断多个元素,不如使用试除法+剪枝判断单个元素;

上面的朴素算法以及各种优化方法,都是对给定的单一数字进行判断,从而得知这个数字是否为素数。但在实际问题中,往往需要获取一个区间内所有素数,或者在短时间内多次查询判断。应对这样的需求,我们会进行预处理:对某一区间进行素数挑选,把素数挑选出来,存储到另外一个地方或者标记起来。

接下来介绍的这两种算法,正好是把某一区间内的素数都筛选出来,且时间复杂度也不高。

#define n 10010 vector<bool> isPrime(n + 1, true);//标记i位置是否为素数 void init_prime() { for (int i = 0; i < n; ++i) { if (i <= 1) isPrime[i] = false; else if (isPrime[i]) { for (int j = 2; i * j < n; ++j) {//我们标记存在的组合中存在最小的素数 isPrime[i * j] = false; } } } }

但是这种一会存在一种弊端,当我们的值为12时,由于12=2*6=3*4,这样我们标记的时候,就会形成重复标记,会增加时间复杂度

因为我们是素数去乘以自然数,可能就会乘到不同素数的倍数,导致重复探测

3.线性筛

我们来分析一下重复标记的原因:在上面的埃式筛中,当我们遇到素数后,将它的倍数全部标记,由此可以推断:一个数被重复标记的原因是因为它是不同质数的因数。

也就是说,我们使用了多个质因数去标记了这个合数。

例如:

12被2和3标记过,30被2、3、5同时标记过。

分析出了原因,优化方向就呼之欲出了:

我们只要使用最小质因数去标记这个数(十分重要,这是线性筛的核心原理所在)就行了,具体该怎么做呢?

具体来说就是维护一个标记数组 arr 和一个已有素数数组 primes ,然后,我们从2开始遍历所有数 i ,并且:(接下来这两条好好理解!!核心部分!!)

①把遇到所有未被标记为合数的数 i (埃式筛中从小到大遍历时遇到的一个个质数)存到 primes 里去;

②以 i 为第一个因子,分别以 primes 里每个质数 j 为第二个因子,求积,可以断定 j∗i 必为合数,故标记之;同时,若 mod(i,j)==0 ,说明 j 是 i∗j 的一个质因数,又因为 primes 数组中的元素是递增的, j 是第一个可以除断 i 的,故可断定 j 是 i 的最小质因数,同时也是 i∗j 的最小质因数,那么更进一步也可断定j 之后的质数 j′ 一定不是 i∗j′ 的最小质因数,故结束 primes 的遍历。

#define n 10010 vector<bool> isPrime(n + 1, true);//标记是否为素数 vector<int> prime;//存储最小素数 void init_prime() { for (int i = 0; i <= n; ++i) { if (i <= 1) isPrime[i] = false; else { if (isPrime[i]) {//是素数 prime.push_back(i); } for (int j = 0; j < prime.size() && i * prime[j] <= n; ++j) { isPrime[i * prime[j]] = false; if (i % prime[j] == 0) break; } } } }
http://www.jsqmd.com/news/778148/

相关文章:

  • HookLaw:用React Hooks范式统一管理JavaScript副作用
  • FPGA与PC高速数据通道:基于FTDI同步FIFO的实战设计
  • 2026年设计师必备:十大电商主图、印刷行业图片与样机素材优质网站推荐 - 品牌2025
  • 2026年5月济南建设工程/股权/知识产权/租赁/合同纠纷处理指南:为何刘迅律师是您的优选专家? - 2026年企业推荐榜
  • Eclair:将Datalog逻辑程序编译为LLVM原生代码的实验性编译器
  • SAFE框架:提升LLM长文本生成质量的关键技术
  • 大语言模型逻辑键结构:原理、分析与优化实践
  • Docker容器化部署SoulseekQt:实现音乐共享服务的无头化与网页访问
  • 2026年GPON OLT厂家推荐:国内主流品牌实力解析,高性价比选型指南 - 速递信息
  • Claude Context:基于MCP与向量数据库的AI编程助手代码库语义搜索方案
  • Cursor设备ID修改脚本解析:原理、风险与合规替代方案
  • 分布式代理节点动作对齐检测与纠正技术解析
  • 基于OpenAI GPT构建轻量级垃圾信息检测器:从原型到安全部署
  • 01-紧固件MES系统 — 系统总览与架构
  • SCICOQA数据集:解决论文与代码一致性问题的关键技术
  • 开发AI应用时如何利用Taotoken进行灵活的模型选型与切换
  • 2026年五大高效方案:大量设计文件归档工具推荐 + 带智能搜索的图片管理工具必备清单 - 品牌2025
  • SPG:扩散语言模型的强化学习优化策略
  • Transformer Lab:AI研究的操作系统,统一模型实验与集群管理
  • 2000 元的口服抗衰产品测评:细胞级抗衰,为什么首选斐萃鎏金瓶 - 速递信息
  • 命令行光标增强工具:动态上下文感知与效率提升实践
  • HMCL启动器跨平台架构深度解析:多操作系统与多架构兼容性技术实现
  • 终端AI编程助手codai:基于Tree-sitter的上下文感知代码生成与重构
  • 双流潮汕火锅店排行:鲜切品质与场地适配实测对比 - 真知灼见33
  • Libwebsockets:从嵌入式到云端的C语言全能网络库实战指南
  • 从零构建可编程治理框架:智能合约与DAO实践指南
  • 2026年合肥留学中介机构测评,低GPA学生如何选最好的机构 - 速递信息
  • 2026年甘肃美术培训学校哪家好?优质美术集训机构深度解析 - 深度智识库
  • 多语言可视化编程工具VisCoder2的设计与实现
  • Infini-Attention:突破Transformer长上下文瓶颈,实现高效无限序列处理