蒟蒻写文,难免疏忽,欢迎来踩!
引例:
假设现在有一个整数n,请求出1..n以内的素数个数。
请注意:n属于1..6×107。
思路:
我们首先考虑朴素算法,但是由于数据范围问题我们一定不能使用朴素方法(即使是开根号的埃氏筛也不可以),因此考虑线性筛。
考虑欧氏筛。欧氏筛,全称欧拉筛法。埃氏筛的主要思想是一个素数a,无论乘以素数或者和数,其所得一定是和数。因此我们可以从2开始,先将答案计数器加一(因为2),然后再将2以及其的倍数标记为和数。第二次操作从未被标记的数中选取最小的数开始。值得注意的是未标记的数中最小的一定是素数,这是因为如果它是一个合数那么它的素因数一定在之前的遍历被遍历到,那么它也会被标记为和数。如此循环下去,直至我们选取的未标记最小数出界为止。
那么现在给出C++源代码:
1 /* 2 import guide: 3 NUM should be define as a data type according to requirements. 4 flag[MAXI] should be set as the auxilary array that mark the visited numbers. 5 prime[MAXI] should be set as the array that stores the prime numbers. 6 */ 7 NUM EulerFilter(NUM limit){ 8 NUM prime_ptr=0; 9 for(NUM prime_head=2;prime_head<=limit;prime_head++){ 10 if(!flag[prime_head]) prime[prime_ptr++]=prime_head; 11 for(NUM ptr=0;ptr<prime_ptr&&prime_head*prime[ptr]<=limit;ptr++){ 12 flag[prime_head*prime[ptr]]=1; 13 if(prime_head%prime[ptr]==0) break; 14 } 15 } 16 return prime_ptr; 17 }
欧氏筛的时空复杂度
欧氏筛的时间复杂度是O(n),因为欧氏筛对于每一个数字只遍历一次。
欧氏筛的空间复杂度是O(n),因为欧式筛需要存储每一个数字的访问标记和找到的所有素数。