埃氏筛法和线性筛

1|0埃氏筛法和线性筛

1|1埃氏筛法

如果一个数是合数,那么它一定有素数因子;

证明:反证法,如果一个数是合数,且其所有因子都是合数。 ----------------------(1)

如果(1)式正确,那么 4 为合数,其因子应为合数,但是 2 显然为素数,所有(1)式不成立;

1|0埃氏筛法就是将 素数 的倍数全部筛掉

代码如下

const int N = 1e6 + 10;
int primes[N], ans; //全局变量 自动赋值为 0
bool st[N]; //全局变量 自动赋值为 false
void get_primes(int n) {
for (int i = 2; i <= n; ++i) {
if (!st[i]) {
primes[ans++] = i;
for (int j = i + i; j <= n; j += i) {
st[j] = true;
}
}
}
}

1|0问题

看到这段代码,不知道你会怎么想,是不是也恰好有一下几个问题呢?

  1. 为什么 n2 开始循环
  2. if 判断语句 () 里面的 !st [i] 是什么意思
  3. primes[ans++] = i 是什么意思
  4. 第九行 for 循环里面的 j 为什么初始化为 i+i
  5. 为什么 j += i

1|0解答

  1. 因为 10 都不是素数;在判断之前,我们在初始条件的时候,默认的所有数都是素数;
  2. 因为我们默认所有数字都是素数,但是,bool 数组却默认初始化为 false ===> , 所有用取反 来表示我们的原本的意思
  3. 如果这个数是素数,也就是这个数没被其他素数筛掉,我们就认为它是素数,就把他存到数组里面
    1. 这两条都是说,我们要把素数的倍数全部筛掉。

1|0新问题

我们发现,埃氏筛法虽然无限逼近线性 O(n),但它却不是线性的,因为它还有可以 优化 的地方

  • 当我们其中一个合数 6 进行分析的时候,我们不难发现,6 既被 2 筛一次,又被 3 筛一次;
  • 如果继续观察其他合数,我们可以发现,大多数的合数的素数因子不唯一
  • 那么问题来了,有没有一种方法可以让一个合数只被它的最小质因子筛掉呢?

答案是有的,线性筛!

在这之前,需要补充一下上面题解的 java 版本

class fun{
int[] primes = new int[1000010];
boolean[] st = new boolean[1000010];
int ans;
public void get_primes(int n){
for(int i=2; i<=n; ++i){
if(!st[i] ){
primes[ans++] = i;
for(int j=i+i; j<=n; j+=i){
st[j] = true;
}
}
}
}
}

1|2线性筛

1|0在阅读本部分之前,请确保你已经看懂了埃氏筛法

先上代码

const int N = 1e6 + 10;
int primes[N], ans;
bool st[N];
void get_primes(int n) {
for (int i = 2; i <= n; ++i) {
if (!st[i]) {
primes[ans++] = i;
}
//重点部分
//start
for (int j = 0; primes[j] <= n / i; ++j) {
st[primes[j]*i] = true;
if (i % primes[j] == 0) {
break;
}
}
//end
}
}

1|0重点部分的理解

  1. j 为什么从 0 开始
  2. 为什么要 primes[j] <= n / i
  3. 这句话什么意思 st[primes[j]*i] = true
  4. 为什么要判断这句话 if (i % primes[j] == 0)

1|0解答部分

  1. 因为我们要从最小的素数开始,将两数乘积的所有值都筛掉。之所以从 0,也是为了满足,每个合数只被它最小的质因子筛掉

  2. 这取决于我们筛数的范围 st[ ] 里面的值不难大于 n

    st[primes[j]*i] = true
  3. 在这个问题上,我发现语言竟是如此的缺乏说服力,建议拿草稿纸演算一下。看看是否解决了 6 被 2 和 3 除两遍的问题

    for (int j = 0; primes[j] <= n / i; ++j) {
    st[primes[j]*i] = true;
    if (i % primes[j] == 0) {
    break;
    }
    }
  4. (1.)当 i % primes[j] == 0 成立, 则 primes[j] 一定是 i 的最小质因子;所有 primes[j] 也一定是 i * primes[j] 的 最小质因子

    (2.)当 i % primes[j] == 0 不成立,则 primes[j] 一定是 i ***** primes[j] 的最小质因子,因为 j 是从 0 开始循环的;

那么为什么当判断语句成立的时候我们要跳出循环呢

假设 i = x * primes[j] ,如果不跳出循环,则下一个被筛掉的数 primes[j+1] i 的最小质因子一定不是 primes[j+1] 而是primes[j]* ,就不符合条件。

java实现(面向数据编程)

class fun{
int cnt;
boolean[] st = new boolean[179424822];
public void get_prime(int[] prime){
for (int i = 2; i <= 179424821; i ++ )
{
if (!st[i]) prime[cnt ++ ] = i;
for (int j = 0; prime[j] <= 179424821 / i; j ++ )
{
st[prime[j] * i] = true;
if (i % prime[j] == 0) break;
}
}
}
}

1|3完结撒花!


__EOF__

本文作者userName
本文链接https://www.cnblogs.com/codezzzsleep/articles/16042374.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   codezzzsleep  阅读(74)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示