埃拉托色尼筛法的复杂度估计与改进 及线性时间筛法简介

本文研究用以求出1~n内的所有素数的算法——埃拉托色尼筛法(the Sieve of Eratosthenes),估计其算法复杂度,并介绍其改进——线性时间筛法。以下内容谢绝转载。                                                                                                                                                                                                                                                                                                                                                                                                        

 

1.埃拉托色尼筛法(the Sieve of Eratosthenes)

埃氏筛法是一种古老的筛选素数的方法,以古希腊数学家埃拉托色尼的名字命名。

算法思想是从1~n中依次删除2的倍数,3的倍数,.......,从而得到所有的素数。

算法伪码:

用$A[i]$表示$i$是否为素数,是为true,否为false。初始化$A[2 \cdots n]=true$.

for $i=2$ to $\sqrt n$

  if $A[i]$ is true

    for $j=2$ to $n/i$

      $A[i*j]$=false;

    end

  end

end

输出:

all $p$ s.t. $A[p]$ is true

 

由于合数$N$一定有不超过$\sqrt N$的质因子,因此外层循环只需循环到$\sqrt n$

 

2.埃氏筛法的复杂度估计

复杂度估计可以如下简单地考虑:外层循环是 $i$ 时,内层循环共执行 $\frac{n}{i}-1$ 次。因此总的时间消耗为:

$$\sum_{primes \, p\le \sqrt n} \frac{n}{p}-1 = n \sum_{primes \, p \le \sqrt n} \frac{1}{p} - \pi(n)$$

其中$\pi(x)$表示不超过$x$的素数个数。根据素数定理,$\pi(x)=\Theta(\frac{x}{\ln x})$

根据Mertens' 2nd theorem:

$$\lim_{n\to\infty} \sum_{primes \ p \le n}\frac{1}{p} -\ln\ln n =M$$

其中$M$是Meissel-Mertens常数,约为$0.26$

由此可见算法的时间消耗为$\Theta  (n \log \log n)$

 

注:一个小优化

可以将内层循环的从$j=i$而不是$j=2$开始。这是因为一个合数一定在$i$是其最小素因子时所标记过,因此只要考虑$j$比$i$大的情况就可以了.

但是这个优化对复杂度的阶并没有改进。这是因为对于不超过$\frac{1}{2}\sqrt n$的素因子来说,以上优化只减少了至多一半的操作量(证明留作习题)

然而上述求和即使把求和上限改成$\frac{1}{2}\sqrt n$,其阶仍然有$\Omega (n \log \log n)$,因此这只是一个常数级别的优化。

 

3.埃氏筛法的改进——线性时间筛法

从上述分析可以看出,埃氏算法并不是一个线性时间算法。事实上,这是因为对于一个合数而言,它有多少个素因子,就被标记成合数多少次。这对于约数较多的数是很慢的。

埃氏筛法有一个简单的改进,使得其复杂度降低到线性时间。我们称它为线性时间筛法。

 

算法伪码:

用$A[i]$表示$i$是否为素数,是为true,否为false。初始化$A[2 \cdots n]=true$。维护一个数组q,存放所有的素数。num表示q中质数的数量,初始为0.

for $i=2$ to $n$

  if $A[i]$ is true

    num=num+1;

    q[num]=i;

  end

  for $j=1$ to num

    $p$=$q[j]$;

    $A[i*p]$=false;

    if $p|i$ break;

  end//其实这个循环的意思就是,对所有不超过 $i$ 最小素因子的素数p,将 $i*p$标记为合数

end

输出:

q[1...num]

下面证明算法的正确性和线性时间性。

容易看出,一个数$k$被算法标记为合数当且仅当存在$p$和$i$使得$k=ip$,且$p$不超过$i$的最小素因子。这也就是说$p$是$k$的最小素因子。

对于合数$k$来说,这表明它仅被标记为合数一次.

而对于素数$k$来说,由于标记为合数要求$k=ip,i,p\ge 2$,因此它不会被标记为合数。

因此,算法是正确的,也是线性时间的。于是我们完成了证明。

 

 

References:

Mertens' 2nd theorem:

http://en.wikipedia.org/wiki/Mertens%27_theorems

posted on 2014-08-22 22:42  德安城  阅读(2894)  评论(0编辑  收藏  举报

导航