在对先前有关Eratosthenes筛子的
帖子的评论中,提到了
Wikipedia的这种简短算法:
算法1:1: i := 2, 3, 4, ..., n: 2: lp[i] = 0: 3: lp[i] := i 4: pr[] += {i} 5: p pr p ≤ lp[i] p*i ≤ n: 6: lp[p*i] := p : lp - n pr - n.
该算法很简单,但并不是所有人都看得出来。 主要问题是维基百科上没有证据,并且到源的
链接 (
pdf )包含与上述算法完全不同的算法。
我希望,在本文中,我将尝试证明该算法不仅有效,而且对于线性复杂度也可以实现。
关于算法复杂性的注释尽管此算法在O上比Eratosthenes的标准
筛网渐近地快(n log log n),但它需要更多的内存。 因此,对于真正大的n,无论此算法在其所有荣耀中闪耀何处,都不适用。 但是,如果您不仅需要查找所有素数,而且还需要快速分解所有不超过n的数,那么即使对于较小的n,它也非常有用。
定义
\数学P -很多素数
l p ( x ) -最小最小素数:
lp(x)=常数\ {p \ in \ mathcal {P} \ \ vert \ p \ vert x \}lp(x)=最小值\ {p \ in \ mathcal {P} \ \ vert \ p \ vert x \}r d ( x ) -其他因素:
r d ( x ) = x / l p ( x )请注意,以上所有定义都是针对
x g e 2 。
上面介绍的功能的一些明显属性,将在以后使用:
升p (一个\乘以 b ) = 米我Ñ (升p (一),升p ( b ))rd(x)<xp in mathcalP=>lp(p)=p证明
引理1 :
lp(x) lelp(rd(x)), forallx notin mathcalP,x>1证明 :因为 任何除数
rd(x) 也是一个分隔线
x 和
lp(x) 不胜于任何除数
x 然后
lp(x) 不超过任何除数
rd(x) 包括最小的。 该语句的唯一问题是
rd(x) 没有简单的除数,但这只有在
x in mathcalP ,在引理条件下被排除。
\平方让
E = \ {(lp(x),rd(x))\ vert \ forall x \ notin \ mathcal {P},2 \ le x \ le n \}因为
lp(x)\乘rd(x)=x (根据定义
rd() ),如果我们得到了很多
E 然后我们可以计算
lp() 对于所有不超过n的复合数字。 例如,这可以通过以下算法完成:
算法2: 1: (l,r) E: 2: lp[l*r] := l;
注意
vertE vert len 因此,上面的算法2适用于线性复杂度。
此外,我将证明Wikipedia的算法1实际上只是对该集合的所有元素进行迭代,因为可以用不同的方式对其进行参数化。
让
E'= \ {(p,r)\ vert p \ in \ mathcal {P},2 \ le r <n,p \ le lp(r),p \ times r \ le n \}引理2 :
E=E′证明 :
让
(a,b)\在E =>
\存在x notin\数学P, 2 lex len mida=lp(x),b=rd(x) 。
根据定义
lp(),rd() :
a in mathcalP ,
a\乘以b=x 。 通过引理1,
a lelp(b) 。
因为
rd(x)<x 然后
b<n 。
由于
x notin mathcalP ,
b ge2 。
另外,根据定义
E ,
x len 因此
a\倍b len 。
全部4个条件
E′ 履行手段
(a,b)\在E′ =>
E\子集E′ 。
让
(a,b)\在E′ 。 让
x=a\乘以b 。
根据定义
E′ ,
a in mathcalP 。 均值
一 -简单的划分
x 。
lp(x)=lp(a\乘以b)=min(lp(a),lp(b))=min(a,lp(b))因为
a lelp(b) 然后
lp(x)=a。 均值
b=rd(x)根据定义,
x=a\乘以b len 也很明显
x=a\乘以b ge2的所有条件
E 完成=>
E′\子集E.因此
E=E′。\平方现在仍然有必要找出正确的
和
p 从集合的定义
E′ 并应用算法2。这正是算法1所做的(仅使用i变量而不是r)。 但是有问题! 排序集合中的所有元素
E′ 计算
lp, 我们需要知道
lp, 因为定义中有条件
p lelp(r) 。
幸运的是,这个问题可以解决正确的排序顺序。 有必要理清
在外循环中,以及
p -在里面。 然后
lp(r) 将已经计算出来。 以下定理证明了这一事实。
定理1:算法1支持以下不变量:在对i = k的外循环进行迭代之后,直到pr(包括k)的所有素数都将在pr中突出显示。 也将算在内
lp() 对于所有
x notin mathcalP midx len, rd(x) lek 在lp数组中。
证明 :
我们通过归纳证明。 当k = 2时,手动检查不变量。 唯一的质数2将添加到pr列表中,因为lp []数组最初使用零填充。 另外,唯一的化合物编号
rd(x) le2 -这是4。很容易验证内部循环将只执行一次(对于n> 3)并正确执行lp [4]:= 2。
现在假设不变量对于迭代i = k-1成立。 让我们证明它对于迭代i = k也将是有效的。
为此,只需检查数字i(如果为质数)将被添加到列表pr中,
lp() 将计算所有复合数字
x len, 包括
rd(x)=i。 这些来自k不变式的数字尚未被k-1不变式覆盖。
如果i很简单,则lp [i]将为0,因为对数组lp的唯一写操作(理论上可以计算lp [i](在第6行))总是写到复合索引,因为p * i(对于i> 1)-总是复合的。 因此,数字i将被添加到素数列表中。 同样,在第3行中,将计算lp [i]。
如果i是合成的,那么在迭代开始时lp [i]就已经由i = k-1的不变量计算出来了,因为
rd(i)<i 或
rd(i) lei−1, 因此,我在上一次迭代中处于不变条件下。 因此,合成数字i不会添加到素数列表中。
此外,具有正确的lp [i]和所有素数,直到i(含i)为止,第5-6行中的循环将迭代所有元素
(p,i) E′ 其中第二部分是我:
- p\在P, 因为它来自列表pr
- p lelp(i), 根据条件停止循环
- p\次i len, 根据条件停止循环
- i<n, 从... p\次i len, p>1
pr列表中所有必要的素数是,因为 最多不超过
lp(i) lei 。 因此,将为所有复合数字计算lp []值
x 为此
rd(x)=我 。 这些恰好是从k-1不变式到k不变式转换过程中丢失的所有数字。
因此,对于任何i = 2..n,不变量成立。
\平方通过定理1中i = n的不变量,可以得出直到n的所有素数,所有lp []都将由算法1计算。
此外,由于在第5-6行中对集合的各个元素进行了排序
E ,则整个内部循环将不再执行
vertE vert<n 操作。 循环中的检查操作将顺利运行
vertE vert+n−1<2n 次(
\版本。 Ë \版本。 次将返回true,n-1次,对于每个i,将返回false)。 所有剩余的操作都在i中从2到n的一个循环中嵌套。
因此,算法1的复杂度为O(n)。