质数筛选算法:The Sieve of Eratosthenes

质数

       质数(prime number)也叫素数,为大于1的且除1和本身以外不再有其他因数的自然数,与之相对的是合数。质数有无限个。

 

性质

·质数只有两个因数:1和本身
·任何大于1的自然数,要么本身是质数,要么可以分解为几个质数之积,且这种分解是唯一的
·质数的个数是无限多的
·若n为正整数,在n²到(n+1)²之间至少有一个质数
·若n为大于等于2的正整数,则n到n!之间至少有一个质数
·若质数p为不超过n(n≥4)的最大质数,则p>n/2
·所有大于10的质数中,个位数只有1,3,7,9

 

 

埃拉托色尼筛选法

       尽管质数有无限多个,但人们还是经常会问某一范围的质数个数。埃拉托色尼筛选法(The Sieve of Eratosthenes),简称埃氏筛法,是解决这一问题的常见算法。
       埃拉托色尼筛选法基于一项基本性质:任何大于1的自然数,要么本身是质数,要么可以分解为几个质数之积,且这种分解是唯一的。
       以LeetCode上的一道题为例。寻找所有小于非负整数n的质数的数量,埃拉托色尼筛选法是这么工作的。

 

       假设从起点开始(起点可由要求指定)的所有数都是质数。从起点开始向前搜寻,若为质数,则将其倍数(不超过上界n)标记为非质数。例如2为质数,则标记4,6,8, ...这些2的倍数都为非质数,然后标记下一个……依此类推。

class Solution1 {
public:
    size_t countPrimes(size_t n) {
        bool *p = new bool[n+1];
        size_t i, j;
        for (i = 0; i <= n; ++i)
            p[i] = true;
        p[0] = p[1] = false;
        for (i = 2; i < n; ++i)
                if (p[i])
                    for (j = 2; i*j < n; ++j)
                        p[i*j] = false;
        size_t cnt = 0;
        for (i = 2; i < n; ++i)
            if (p[i])
                cnt++;
        delete []p;
        return cnt;
    }
};

        由流程图可知,在筛选过程中我们进行了很多重复筛选。实际上在内层循环中,只要从i*i开始筛就可以了,因为i*2, i*3, ..., i*i-1都被筛过了。

class Solution2 {
public:
    size_t countPrimes(size_t n) {
        bool *p = new bool[n+1];
        size_t i, j;
        p[0] = p[1] = false;
        for (i = 2; i <= n; ++i)
            p[i] = true;
        for (i = 2; i < n; ++i)
                if (p[i])
                    for (j = i*i; j < n; j += i)
                        p[j] = false;
        size_t cnt = 0;
        for (i = 2; i < n; ++i)
            if (p[i])
                cnt++;
        delete []p;
        return cnt;
    }
};


       埃拉托色尼筛选法实现简单,缺点是对空间的需求量大。对于这一点,我们可以用位图存储,这样就可以大大减少空间需求量。
 

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值