欧拉筛法

Posted popodynasty

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了欧拉筛法相关的知识,希望对你有一定的参考价值。

埃拉托斯特尼筛法可以在 O(nloglogn)的复杂度内筛出素数,但事实上欧拉筛(线性筛)可以达到O(n)的线性效率!

先来看欧拉筛的算法及实现,然后再思考埃氏筛法时间都多在哪了。

欧拉筛算法步骤:

1.如果上界小于2,没有素数,返回。

2.标记i=2为第一个素数。然后如果没有到达上界,转移到步骤3,否则转移到步骤5。

3. 令i自增1。检验i是否是素数,如果是素数,将其填入素数数组中,转移到步骤4。

4.,无论它是不是素数,都将它与目前已经找到的素数的乘积判定为合数。如果某一个素数可以被当前这个数 i 整除,或者所有已经选出的素数都已经遍历过,或者当前素数*i后大于上界,转移到步骤5。

5.到上界后,返回。否则转移到步骤3。

 1 #include <iostream>
 2 #include <vector>
 3 using namespace std;
 4 void get_prime(vector<int> & prime,int upper_bound){ // 传引用
 5     if(upper_bound < 2)return;
 6     vector<bool> Is_prime(upper_bound+1,true);
 7     for(int i = 2; i <= upper_bound; i++){
 8         if(Is_prime[i])
 9             prime.push_back(i);
10         for(int j = 0; j < prime.size() and i * prime[j] <= upper_bound; j++){
11             Is_prime[ i*prime[j] ] = false;
12             if(i % prime[j] == 0)break;// 保证了一个数只被筛一次。
13         }
14     }
15 }
16 int main(){
17     vector<int> prime;
18     get_prime(prime, 10000001);
19     for(vector<int> :: iterator it = prime.begin(); it not_eq prime.end(); it++)
20         cout<<*it<<" ";
21     return 0;
22 }

可以看出,欧拉筛法和埃氏筛法的主要不同之处有两点:

1.筛选方式不同:埃氏筛法是针对每一个素数z,一次性筛除z的所有倍数。而欧拉筛法则是一步步筛掉一个素数的倍数。

看看埃氏筛法的时间都多在哪了?比如数6,它被2、3重复筛除了两次。数42,被2、3、7筛过三次。那么不妨将n个素数相乘,对于这个乘积,我们一共多筛了n-1次!如何避免这种多余的工作呢?看下一条。

2.欧式筛法的关键特别之处在于一条语句: if(i % prime[j] == 0)break; 这条语句保证了,每一个合数都只被筛除一次。为什么呢?由于  i % prime[i] == 0 ,那么如果继续筛下去,i * prime[j+1]一定也会是某一个合数,那么如果下一次判断这个合数的时候,它依然会被 prime[j] 筛掉。虽然prime[j+1] 也可以筛除它,不过它已经被prime[j]筛过了,prime[j+1]的筛除工作是多余的。

以上是关于欧拉筛法的主要内容,如果未能解决你的问题,请参考以下文章

欧拉筛法

质数判断(欧拉筛法)

线性筛法(欧拉筛法)求素数

埃氏筛法&欧拉筛法

欧拉筛法

欧拉筛转载自用