首页 > 编程语言 >C++实现欧拉筛法

C++实现欧拉筛法

时间:2024-03-19 11:58:18浏览次数:30  
标签:prime 筛时 筛法 队列 C++ 素数 筛掉 欧拉

Euler筛法介绍

以筛出100以内(含100)的所有素数为例来说明一下欧拉筛法的原理。

和Eratosthenes筛法一样,Euler筛法也从2开始筛,但Eratosthenes筛法会把2的倍数一批全部筛掉,而Euler筛法用2筛时仅仅把2*2(即4)筛掉,而把其它偶数留到后面再筛掉,从而避免了一个偶数被多次筛除带来的性能开销,比如偶数6、8、10,在随后用3、4、5筛的时候会被筛掉。

Euler筛法引入了一个素数队列,从2开始没被筛掉的数会依次加进素数队列,当用3筛时,素数队列里有2和3两个素数,这时会筛掉3*2(即6)和3*3(即9)。

当用4筛时,4因为之前被2筛掉了,所以4不会加进素数队列,此时素数队列里依然只有2和3两个素数,这时会筛掉4*2(即8),但4*3(即12)并不在这时筛掉,这是因为4本身是素数2的倍数,即4*3里不能保证3是最小素因数。

当用5筛时,先把5加入素数队列,随后筛掉5*2(即10)、5*3(即15)和5*5(即25)。

当用6筛时,6因为之前被3筛掉了,所以此时素数队列里依然只有2、3、5,这时会筛掉6*2(即12),但因为判断出6是2的倍数,随后就不会用6进一步去筛掉6*3(即18)。

当用7筛时,先把7加入素数队列,随后依次筛掉7*2(即14)、7*3(即21)、7*5(即35)和7*7(即49)。

当用8筛时,8因为之前被4筛掉了,所以此时素数队列里依然只有2、3、5、7,这时会筛掉8*2(即16),但因为判断出8是2的倍数,随后就不会用8进一步去筛掉8*3(即24)。

当用9筛时,9因为之前被3筛掉了,所以此时素数队列里依然只有2、3、5、7,这时会筛掉9*2(即18)和9*3(即27),但因为判断出9是3的倍数,随后就不会用9进一步去筛掉9*5(即45)。

当用10筛时,10因为之前被5筛掉了,所有此时素数队列里依然是2、3、5、7,这时会筛掉10*2(即20),但因为10是2的倍数,随后不会用10去筛掉10*3(即30)。

当用11筛时,先把11加入素数队列,随后依次筛掉11*2(即22),11*3(即33),11*5(即55),11*7(即77)。11*11(即121)因为大于100而不在筛查范围。

用12筛,只会筛去12*2。

用13筛,13进素数队列,随后依次筛去13*2,13*3,13*5,13*7。13*11不在筛查范围。

用14、15、16筛,依次会筛去14*2、15*2和15*3、16*2。

用17筛,17进素数队列,随后依次筛去17*2、17*3、17*5。17*7不在筛查范围。

……

用49筛,会筛去49*2。49*3不在筛查范围。

用50筛,会筛去50*2。50*3不在筛查范围。

用51筛,不会筛去任何数,因为51*2>100。

随后用52、53、……、99、100筛的过程里,都不再会筛去任何数,而只有素数进素数队列的行为。

由上述过程可知,欧拉筛法的核心思路是:对于筛查范围内的任意一个合数m,只使用m中除m之外最大的因数把m筛去。例如,45=3*3*5,确保用15筛去45即可。更一般的情形,m=p1*p2*……*ps,其中p1、p2、……、ps均为素数且满足p1<=p2<=……<=ps,则确保用p2*……*ps筛去m即可。

Euler筛法核心思路及证明

当此时取出的素数表中的素数(即枚举的最小质因子)整除于当前枚举的合数时,我们就停止循环素数表,开始枚举下一个合数。

证明如下:

设当前枚举的最小质因子prime[i]整除于合数n时,即我们要筛掉合数 n*prime[i] ;如果我们此时不退出,继续枚举下一个素数prime[i+1],对于将要筛掉的合数 n*prime[i+1] 由于插入顺序从小到大,则 prime[i+1]>prime[i]。由于prime[i]整除于合数n,所以必然合数 n*prime[i+1] 还可以被分解为

显然,在上面的分解方式中,我们将要筛掉的合数分解为更小的质因子 prime[i] ,这不符合我们对于每一个数被唯一分解的要求,所以我们可在代码中加入一行判断整除关系的代码进行优化。

Euler筛法的C++程序实现

#include<bits/stdc++.h>
using namespace std;
bool IsPrime[100005];
int prime[50005];

int eulerSieve(int n) {
    int top = 1;
    memset(IsPrime, 1, sizeof(IsPrime));
    for (int i = 2; i <= n; i++) {
        if (IsPrime[i])
            prime[top] = i, top++;
        for (int j = 1; j < top; j++) {
            if (i * prime[j] > n)
                break;
            IsPrime[i * prime[j]] = 0;
            if (i % prime[j] == 0)
                break;
        }
    }
    return top;
}
int main()
{
    int n, num;
    cin>>n;
    num= eulerSieve(n);
    for(int i=1;i<=num;i++)
    {
        cout<<prime[i]<<" ";
    }
    return 0;
}

 

标签:prime,筛时,筛法,队列,C++,素数,筛掉,欧拉
From: https://www.cnblogs.com/end/p/18082442

相关文章

  • C++STL第五篇(链表List的使用方法)
    list链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。相......
  • C++刷题杂记
    目录C++中如何声明二维vectorC++中如何声明二维vector在C++中,你可以使用嵌套的std::vector来声明一个二维的vector。每个元素本身是一个std::vector,而这些元素的集合构成了外部的std::vector。以下是如何声明一个二维vector的示例:#include<vector>intmain(){//声......
  • C++类实现顺序表
    环境:vscodesequencelist.h#ifndefSEQUENCELIST_H#defineSEQUENCELIST_H#defineMAXSIZE20//最大存储容量typedefintElemType;classSqList{public:SqList();//SqList(ElemTypeelems[],intn);//有参构造器~SqLis......
  • 字符串压缩(C++)
    字符串压缩:    例如:aaaabbbccx-->4a3b2cx,单个字符不压缩。基本思想:前后两两字符作比较,若相同则计数器加一,若不同则直接输出。程序代码:#include<iostream>intmain(){ strings; intcount=1; cin>>s; s=s+"";//加上空格是为了方便最后一个字符的比较 in......
  • 【c++】string类---标准库(STL)中的string类
    主页:醋溜马桶圈-CSDN博客专栏:c++_醋溜马桶圈的博客-CSDN博客gitee:mnxcc(mnxcc)-Gitee.com目录1.STL(标准库)1.1什么是STL1.2STL的版本1.3 STL的六大组件1.4 STL的重要性1.5 如何学习STL6.STL的缺陷2.为什么要学习string类2.1C语言中的字符串2.2OJ中......
  • C++进阶之路---手撕“红黑树”
    顾得泉:个人主页个人专栏:《Linux操作系统》 《C++从入门到精通》  《LeedCode刷题》键盘敲烂,年薪百万!一、红黑树的概念与性质1.概念       红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。通过对任何一条从根到叶子的......
  • c++类&对象(学习笔记)
    c++类&对象类,用户定义的类型,类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员,函数在一个类中被称为类的成员。c++类的定义定义一个类,本质上是定义一个数据类型的蓝图这书籍上并没有任何数据,但他定义了类的名称意味着什么,他定义了类......
  • 亲子游戏【华为OD机试JAVA&Python&C++&JS题解】
    题目描述宝宝和妈妈参加亲子游戏,在一个二维矩阵(NN)的格子地图上,宝宝和妈妈抽签决定各自的位置,地图上每个格子有不同的糖果数量,部分格子有障碍物。游戏规则是妈妈必须在最短的时间(每个单位时间只能走一步)到达宝宝的位置,路上的所有糖果都可以拿走,不能走障碍物的格子,只能上下......
  • C++看程序写结果:调用一次Line类构造函数,执行几次Point类复制构造函数?
    C++看程序写结果:调用一次Line类构造函数,执行几次Point类复制构造函数?#include<iostream>#include<cmath>usingnamespacestd;classPoint{//Point类定义public:Point(intxx=0,intyy=0){x=xx;y=yy;}Point(Point&p);......
  • 【CSP考点回顾】C++标准库加速输入输出
    C++标准库加速输入输出ios_base::sync_with_stdio(false);:取消C++标准库(iostream)与C标准库(stdio)之间的同步。默认情况下,为了保证C++的cin、cout与C的stdin、stdout能够互相交换数据,它们之间会进行同步。这样做虽然安全,但会减慢IO操作的速度,因为每次IO操作都需要进行同步。......