质数筛选--快速筛选出小于等于N的质数

原创 2016年08月29日 20:38:30

Eratosthenes筛法(O(nlog^logn) )

此方法非常的简单:
1. 维护一个数组vector<bool> prime(n + 1, true)既让数组中的所有数都为真,表明它是质数。
2. 对于每一个质数,删除它的倍数,因为质数的倍数一定是合数。让后将数组中对应的数改为false,这样就可以避免遍历他。

代码如下:

int findPrime(int n) {
    vector<bool> prime(n + 1, true);
    int res=0;
    for (int i = 2; i <= n; i++) {
        if (prime[i]) {        //判断其是否是素数
            for (int j = 2; j*i <= n; j++)  //删除所有该素数的倍数
                prime[j*i] = false;
            res++;
        }
    }
    return res;
}

上述的筛选速度已经是很快了,但是他有一个问题。比如合数10,在枚举2的时候我们判定了一次,在枚举5的时候我们又判定了一次。因此使得其时间复杂度比O(n)要高

Eular质数筛法

与Eratosthenes筛法不同的是,对于外层枚举i,无论i是质数,还是是合数,我们都会用i的倍数去筛。但在枚举的时候,我们只枚举i的质数倍。比如2i,3i,5i,…,而不去枚举4i,6i…,原因我们后面会讲到。

此外,在从小到大依次枚举质数p来计算i的倍数时,我们还需要检查i是否能够整除p。若i能够整除p,则停止枚举。

利用该算法,可以保证每个合数只会被枚举到一次。我们可以证明如下命题:

假设一个合数k=M*p1,p1为其最小的质因子。则k只会在i=M,primeList[j]=p1时被筛掉一次。

首先会在i=M,primeList[j]=p1时被筛掉是显然的。因为p1是k的最小质因子,所以i=M的所有质因子也≥p1。于是j循环在枚举到primeList[j]=p1前不会break,从而一定会在i=M,primeList[j]=p1时被筛掉

其次不会在其他时候被筛掉。否则假设k在i=N, primeList[j]=p1时被筛掉了,此时有k=N*p2。由于p1是k最小的质因子,所以p2 > p1,M > N且p|N。则i=N,j枚举到primeList[j]=p1时(没到primeList[j]=p2)就break了。所以不会有其他时候筛掉k。

同时,不枚举合数倍数的原因也在此:对于一个合数k=M*2*3。只有在枚举到i=M*3时,才会计算到k。若我们枚举合数倍数,则可能会在i=M时,通过M*6计算到k,这样也就造成了多次重复计算了。

综上,Eular筛法可以保证每个合数只会被枚举到一次,时间复杂度为O(n)。当N越大时,其相对于Eratosthenes筛法的优势也就越明显。

代码如下:

int findPrime1(int n) {
    vector<bool> prime(n + 1, true);
    vector<int> primeList(n+1); int primeCount = 0;
    for (int i = 2; i <= n; i++) {
        if (prime[i]) {
            primeCount++;
            primeList[primeCount] = i;
        }
        for (int j = 1; j <= primeCount; j++) {
            if (i*primeList[j] > n) break;
            prime[i*primeList[j]] = false;
            if (i%primeList[j] == 0) break;
        }
    }
    return primeCount;
}

对于两者的时间测试来看,其差别是非常小的:

int main() {
    clock_t start = clock();
    cout << findPrime1(5000000) << endl; 
    clock_t finish = clock();
    cout<<(double)(finish - start) / CLOCKS_PER_SEC<<endl;        //11.854s
    clock_t start2 = clock();
    cout << findPrime1(5000000) << endl;
    clock_t finish2 = clock();
    cout << (double)(finish2-start2) / CLOCKS_PER_SEC << endl;     //11.81s
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

PAT 乙级 Basic Level 1007. 素数对猜想(素数筛法)

1007. 素数对猜想 让我们定义 dnd_n 为:dn=pn+1−pnd_n = p_n+1 - p_n,其中 pip_i 是第i个素数。显然有d1=1d_1=1 且对于n>1n>1有dn...
  • Dodd9199
  • Dodd9199
  • 2016年03月18日 09:33
  • 542

C#找质数(素数)厄拉多塞筛法

C#找质数(素数)厄拉多塞筛法质数(prime number)又称素数,有无限个。指整数在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数。换句话说,只有两个正因数(1和自己)的自...
  • cadenzasolo
  • cadenzasolo
  • 2016年02月28日 23:47
  • 1841

素数筛选法,快速获取素数序列

今天,学习了[素数][6]求取的方法,感觉很棒,拿来分享一下。首先,对比一下两种方法—普通求取素数的方法和基于筛选法的素数求取方法。...
  • qq_34739984
  • qq_34739984
  • 2016年11月01日 19:57
  • 1330

三种素数筛选法详解 (转)

转自:http://tr0217.blog.163.com/blog/static/3606648020099302135503/ 第一种:剔除2 3 4 5 6 ... ... 的倍数 ...
  • tongyongzh
  • tongyongzh
  • 2011年08月17日 00:19
  • 13690

素数筛选--总结

第一种:直接暴力,在这就不说了 第二种:埃氏筛法(能处理1e6以下的数据) 首先,将2到n范围内的所有整数写下来。其中最小的素数为2,将表中所有2的倍数都划去。表中剩余的最小数字是3,不能被更小的数整...
  • TXT003
  • TXT003
  • 2016年03月26日 12:06
  • 318

素数筛选法 (求1~n的素数)

具体方法就不阐述了,百度一下就能找到,
  • yzj577
  • yzj577
  • 2014年07月26日 18:03
  • 4613

素数筛选法

素数筛选有两种,一种是普通的筛选,O(nlognlogn) 依据是: 1).若X是素数,则X的倍数都不是素数 2).若X不是素数,则X肯定在[1,X)之间被筛选掉。即存在Y,使得k*Y=X,然后Y根...
  • u012469987
  • u012469987
  • 2015年07月22日 10:17
  • 854

小于等于n的素数的个数(埃式筛选法和欧拉筛选)

问题描述给定数字n,求出小于等于n的素数的个数,假设n
  • BeforeEasy
  • BeforeEasy
  • 2017年08月15日 17:32
  • 551

动态规划求小于等于n的质数个数

动态规划求小于等于n的质数个数
  • u012891242
  • u012891242
  • 2016年05月10日 20:25
  • 1586

求n以内的素数个数问题

首先约定n的范围, 1≤n≤10000000; 如何判断一个数m是否是素数,可以有很多种方法,最常见的方法就是 从1-根号m依次实验,然而这个方法的效率较慢,而且对于求n以内素数个数...
  • a1757290629
  • a1757290629
  • 2015年10月19日 15:49
  • 1456
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:质数筛选--快速筛选出小于等于N的质数
举报原因:
原因补充:

(最多只允许输入30个字)