Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 为什么Eratosthenes筛比简单的“过滤”更有效;哑巴;算法?_Algorithm_Performance_Big O - Fatal编程技术网

Algorithm 为什么Eratosthenes筛比简单的“过滤”更有效;哑巴;算法?

Algorithm 为什么Eratosthenes筛比简单的“过滤”更有效;哑巴;算法?,algorithm,performance,big-o,Algorithm,Performance,Big O,如果您需要生成从1到N的素数,那么“愚蠢”的方法是迭代从2到N的所有数字,并检查这些数字是否可以被目前为止发现的小于所讨论数字平方根的素数整除 在我看来,埃拉托什尼的筛子也有同样的作用,只是反过来——当它找到一个素数N时,它就把所有N的倍数都划掉了 但是无论你在找到N时把X划掉,还是检查X是否可以被N整除,基本的复杂性,大O都保持不变。对于一个素数对,仍然要执行一个常量时间运算。事实上,哑巴算法一找到素数就中断了,但埃拉托斯提尼的筛子会将每个数标记好几次——每一个素数可以被它整除一次。除了素数,

如果您需要生成从1到N的素数,那么“愚蠢”的方法是迭代从2到N的所有数字,并检查这些数字是否可以被目前为止发现的小于所讨论数字平方根的素数整除

在我看来,埃拉托什尼的筛子也有同样的作用,只是反过来——当它找到一个素数N时,它就把所有N的倍数都划掉了

但是无论你在找到N时把X划掉,还是检查X是否可以被N整除,基本的复杂性,大O都保持不变。对于一个素数对,仍然要执行一个常量时间运算。事实上,哑巴算法一找到素数就中断了,但埃拉托斯提尼的筛子会将每个数标记好几次——每一个素数可以被它整除一次。除了素数,每个数的运算量至少是素数的两倍


我在这里误解了什么吗?

因为使用筛子法,当运行素数达到N的平方根时,就不再标记运行素数的多次

比如说,你想找到所有小于一百万的素数

首先设置一个数组

for i = 2 to 1000000
  primetest[i] = true
然后进行迭代

for j=2 to 1000         <--- 1000 is the square root of 10000000
  if primetest[j]                                    <--- if j is prime
    ---mark all multiples of j (except j itself) as "not a prime"
    for k = j^2 to 1000000 step j
      primetest[k] = false

对于j=2到1000来说,第一个区别是除法要比加法昂贵得多。即使每个数字都被“标记”了好几次,但与“哑”算法所需的大量除法相比,这是微不足道的。

一个“幼稚”的埃拉托什筛将多次标记非素数。 但是,如果你在链表上有你的数字,并且删除的数字是倍数(你仍然需要遍历列表的其余部分),那么在找到素数之后要做的工作总是比在找到素数之前要少。

本文解释如下:


我认为即使没有Haskell的知识,它也是可读的。

在naive方法中,您对检查素性的每个数字执行
O(sqrt(num))
操作。这是总数

在筛选方法中,对于从1到
n的每个未标记数字,在标记
2
的倍数时执行
n/2
操作,在标记
3的倍数时执行
n/3
,在标记
5的倍数时执行
n/code>操作。这是
n*(1/2+1/3+1/5+1/7+)
,即
O(n log n)
。有关该结果,请参阅

所以渐进复杂性是不一样的,就像你说的。即使是一个朴素的筛子也会很快击败朴素的素代方法。优化版本的筛子可以更快,但大的oh保持不变

这两者并不像你所说的那样是等价的。对于每个数字,你将在朴素素数生成算法中用相同的素数
2、3、5、7、
检查整除性。随着你的进步,你会用相同的数列检查整除性(当你接近
n
时,你会越来越多地检查整除性)。对于筛子,当您接近
n
时,检查的次数会越来越少。首先,您以
2
的增量检查,然后以
3
的增量检查,然后以
5
的增量检查,依此类推。这将击中
n
,并以更快的速度停止。

  • “哑”算法对每个素数都有效
  • 实数算法对每个素数都有效

用大致
N/log(N)
素数相乘。

在试除算法中,确定一个数
N
是否为素数所需的大部分工作是测试素数的可整除性,直到
sqrt(N)

n
是一个素数或几乎相同大小的两个素数(包括素数的平方)的乘积时,最坏情况会出现。如果
n
有两个以上的素数因子,或两个大小非常不同的素数因子,则其中至少有一个比
sqrt(n)小得多
,因此,即使是所有这些数字所需的累积功(占到
N
为止的所有数字的绝大多数,因为足够大的
N
)也相对来说是微不足道的,我将忽略这一点,并假设合成数是在不做任何功的情况下确定的(两个近似相等的素数的乘积在数量上很少,因此尽管它们各自的成本与一个相似大小的素数一样高,但总的来说,这是一个可以忽略不计的工作量)

那么,在
N
之前测试素数需要多少工作量

根据素数定理,素数
0
只有很少几个不同的素数因子,一个简单的估计表明不同的素数因子的数目以
lg n
(以2为底的对数)为界,因此筛外交叉数的上界为
n*lg n

正如IVlad已经做过的那样,通过不计算每一个组合被划掉的频率,而是计算每一个素数被划掉的倍数,我们很容易发现划掉的次数实际上是θ(N*logn)
。同样,使用控制盘不会改变复杂性,但会减少常量因素。但是,在这里,它的影响比试用版更大,因此至少应该跳过EVEN(除了减少工作量外,还可以减少存储大小,从而提高缓存位置)

因此,即使不考虑除法比加法和乘法更昂贵,我们也可以看到筛子所需的运算量远小于试除法所需的运算量(如果限制不太小的话)

总结:
试划分通过划分素数来做徒劳的工作,筛子通过反复删除复合物来做徒劳的工作。素数相对较少,但复合物很多,因此人们可能会认为试划分浪费更少的工作。
B