素数筛法的复杂度

素数筛法的复杂度

Xie Xie给我看了一个链接性能调优--永远超乎想象,里面提到了素数筛法的复杂度,作者用实验发现此筛法是线形的。

所谓素数筛法就是那个求小于n的所有素数最简单的算法:

bool* prime(int n) {
  bool *p = new bool[n];
  memset(p, 0, sizeof p);
  for (int i = 2; i < n; i++)
    if (!p[i])
      for (int j = 2*i; j < n; j+=i)
        p[j] = true;
  return p;
}

此算法复杂度实际为  O(p<nn/p)=O(nloglogn)  。在可以测试的范围内,的确是接近线形的,虽然实际上不是。下面是如何估计  1p  :

loglog===<=ln(n=11n)=lnp11p1=pln(11p1)=pln(1p1)p(1p+12p2+13p3+)=p1p+p1p2(12+13p+14p2+)p(1p+12p2+13p3+)=p1p+p1p2(12+13p+14p2+)p1p+p1p2(1+1p+1p2+)=p1p+p1p(p1)p1p+C(1)(2)(3)(4)(5)

更精确的,

p<n1p=loglogn+Θ(1)

注意此估计可直接得出素数有无穷多个 :D 。

但是纯O(n)的算法也不是没有,只不过需要增加辅助空间保存质数列表:

bool* prime(int n) {
    bool *isp = new bool[n];
    bool *p = new p(int(2*n/log(n)+20));
    memset(isp, 0, sizeof isp);
    memset(p, 0, sizeof p);
    int np = 0;
    for (int i = 2; i < n; i++) {
        if (~isp(i)) p(np++) = i;
        for (int j = 0; j < pn && p[j]*i < n; j++) {
            isp[p[j]*i] = 1;
            if(i%p[j] == 0) break;
        }
    }
    delete p;
    return isp;
}

这个算法的关键在于 if(i%pr[j] == 0) break;。它使得任何一个合数,只被它最小的质因数标记过一次。所以整个算法是线性的。但考虑到log(log(100000000))还不到3,故这个线性算法其实也只有理论上的价值罢了。


ps:如果仅筛去sqrt(n)内因子的倍数,也可以得到所有的素数。复杂度降低为n(loglogn -1),实际上少了n步的操作。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值