菜缤的世界 CairBin's Blog - 线性筛
type: channel
link: https://blog.cairbin.top/index.php/tag/线性筛/
items: 素数寻找算法

素数寻找算法
type: item
date: 2021-10-30T08:45:00+00:00
description: 找素数暴力求解时间复杂度： O(n*sqrt(n))原理暴力求解是对[m,n]的每一个整数都判断是否为素数，由数学可知，一个数i的因数关于sqrt(i)对称分布,故我们只需判断[2,sqrt(i)]的整数中有没有i的因数即可代码vector<int> fuckingFindPrime(int m,int n) { vector<int> prime; if(m<=n) { for(int i=m; i<=n; i++) { bool flag = true; for(int j=2; j<=sqrt(i); j++) //需要调用math.h头文件 { if(!(i%j)){ flag = false; break; } } if(!flag) continue; else prime.push_back(i); } } return prime; }埃氏筛法时间复杂度： O(n*log(n))原理首先，2是最小质数，所以先把2在n以内的所有倍数筛选掉。然后，3也是质数，故把3的所有倍数筛选掉。4不是质数，且4为2的倍数，已经被筛选掉，跳过。5是质数。。。。然后依次类推，最后剩下的就都是质数了。代码 vector<int> EratosthenesSieve(int n) { vector<int> num; vector<int> prime; for(int i=0; i<=n; i++) num.push_back(i);//把[0,n]的整数初始化 num[1] = 0; //1公认不是素数，把1去掉 for(int i=2; i<=n; i++) { if(!num[i]) continue;//被置为0的数不是素数，所以跳过本轮循环去判断下一个位置 prime.push_back(i); //是素数，保存到prime中 //以下为埃氏筛的关键，参考上文的“原理”部分 for(int j=i; i*j<=n&&j<n; j++) num[i*j] = 0; } return prime; }提示如果要寻找区间[m,n]的素数，只需用埃氏筛打表n以内的素数到向量prime（或数组），然后在prime中找到不小于m的最小素数，一直输出到不大于n为止比如，寻找[50,90]的素数，代码可以如下int main() { vector<int> prime = EratosthenesSieve(90); int i=0; while(prime[i]<50) i++; for(int j=i; prime[j]<=90; j++) cout << prime[j] << " "; cout << endl; return 0; }当然，这只是个简单的例子，你也可以用更高效的查找算法于prime中寻找，因为本文主题为寻找素数，所以查找方面不过多叙述欧拉筛(线性筛)时间复杂度： O(n)原理其将合数分为 合数 = 最小质因数*合数 的形式，通过最小质因数判断是否被标记。故相对于埃氏筛，欧拉筛不会反复标记一个合数，效率更高。代码vector<int> EulerSieve(int n) { int pNum = 0; //记录素数的个数 vector<int> prime; vector<bool> isPrime; //用于标记 //对标记向量初始化 for(int i=0; i<n; i++) isPrime.push_back(false); for(int i=2; i<=n; i++) { if(!isPrime[i]) //没有被筛选过，则为素数 { pNum++; prime.push_back(i); } for(int j=0; j<pNum && i*prime[j]<=n; j++) { isPrime[i*prime[j]] = true; //将已经记录的素数倍数标记 //下方为欧拉筛的核心 if(!(i%prime[j])) break; } } return prime; }核心欧拉筛妙就妙在它的核心处若i是prime[j]的整数倍k则i · prime[j+1] = k · prime[j] · prime[j+1] = k · prime[j+1] · prime[j]i · prime[j+1]为 prime[j] 的整数倍，不需要被标记，prime[j+2]...prime[j+...] 同理故该推导告诉我们不需要去标记后面的数，直接跳出循环即可提示欧拉筛法同埃氏筛一样为打表方法，想要获取[m,n]的素数要去查表