-
快速线性筛法
仔细分析埃拉托斯特尼筛法可发现,这种方法会造成重复筛除合数,影响效率。以 30 为例,在 i=2 的时候,k=2*15 筛了一次;在i=5,k=5*6 的时候又筛了一次。为避免冗余,提高效率,也就有了快速线性筛法,其可保证不会重复删除一个数。
根据算术的基本定理——每个合数都可以以唯一形式被写成质数的乘积,所以我们可以把所有素数的集合看成一个“盒子”,那么所有合数其实就是重复从素数这个“盒子”中取两个及以上不分顺序的组合,还是以30为例,我们有235、253、325、352、523、532,共6种取法,在埃拉托斯特尼筛法中,235和325对应6*5、253和523对应10*3、352和532对应15*2,所以共重复了三次。为了不重复取到相同的合数,我们需要一种从素数“盒子”中取素数的取法,这种取法不会因为合数的素数组合相同而顺序不同而取多次。
接下来开始介绍快速线性筛法是如何从素数“盒子”中取素数才不会重复的:
首先我们是筛法所以素数是从小到大按顺序获取的。假设我们已有一个素数序列从小到大排列,例如2、3、5、7,对于由两个素数组成的合数,第一个素数我们可以从小到大取,第二个素数就从最小的素数取到等于第一个素数为止,即22,32,33,52,53,55以此类推,新加入素数时,与新素数相关的合数,只须算新素数分别与小于等于它的素数一遍即可(明确一些条件,即一个合数肯定由小于它的素数组成,一个素数和其他素数的组合肯定大于该素数,所以与新素数有关的合数肯定在新素数之后),接下来是三个素数组成的合数,首先,遇到三素数组成的合数必然先遇到由其中两素数组成的合数(因为三素数中两个素数的积肯定比三素数的积小),例如遇到222之前肯定先遇到22,遇到332和322之前肯定先遇到32,在两个素数的合数的基础上,第三个素数我们只需要从小到大乘到该合数最小的素数即可,例如72就只和2相乘,73就可以和3与2,没必要将72乘以3会和73乘2时重复,四及以上素数的合数同理,以2,3,5为例按以上取法结果为:
两个素数的合数组合:22,32,33,52,53,55
三个素数的合数组合:222,322,332,333,522,532,533,552,553,555
…
如此保证不会如埃拉托斯特尼筛法一样重复筛选同一合数。
#include<vector> vector<int> get_prime(int n) { vector<int> prime; prime.clear(); int cnt=0; int size; bool* p=new bool[n+1]; p[0]=p[1]=false; //0和1不是质数也不是合数 for(int i=2;i<n;i++) p[i]=true; for(int i=2;i<=n;i++) { if(p[i]) prime.push_back(i); size=prime.size(); for(int j=0;j<size&&prime[j]*i<=n;j++) { p[prime[j]*i]=false; if(i%prime[j]==0)//若能整除说明该合数包含该素数,且该合数的最小素数为该素数 break; } } delete[]p; return prime; }
快速线性筛法
于 2023-03-06 16:32:36 首次发布