欧拉筛法
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]的筛除工作是多余的。
以上是关于欧拉筛法的主要内容,如果未能解决你的问题,请参考以下文章