C++ Eratosthenes算法的筛选效率
我正在努力理解“埃拉托什尼筛”。这是我的算法(下面的代码),以及我无法理解的特性列表(按顺序)C++ Eratosthenes算法的筛选效率,c++,algorithm,performance,primes,sieve-of-eratosthenes,C++,Algorithm,Performance,Primes,Sieve Of Eratosthenes,我正在努力理解“埃拉托什尼筛”。这是我的算法(下面的代码),以及我无法理解的特性列表(按顺序) 为什么i*i比i*2更有效?是的,我可以理解它会减少迭代次数,因此效率更高,但它不会跳过一些数字吗(例如I=9是代码> i 的最小倍数,但尚未被消除。(把从1到100的数字写在纸上,用手执行算法查看。)至于i*i问题,它不会跳过任何内容,因为每个小于i^2的数字要么是素数,要么是素数因子小于i,因此在上一步中已经被标记。“根据我的理解,我们有2个完整迭代和1个部分迭代,因此O(n^2*logn)”复杂
i*i
比i*2
更有效?是的,我可以理解它会减少迭代次数,因此效率更高,但它不会跳过一些数字吗(例如I=9
跳过18 27 36…
)
O(n)
,这是可以理解的;无论我们输入什么数字,它都会创建一个输入大小的数组,但这里的时间复杂性让事情变得混乱。我发现这个符号O(n(logn)(loglogn))
——那是什么?根据我的理解,我们有2个完整迭代和1个部分迭代,因此O(n^2*logn)
#包括
使用名称空间std;
int main(){
不能改变大小;
布尔Primersarr[arrSize];
primesArr[0]=假;
对于(inti=1;ij=81跳过18 27 36
你指的是
for (int j = i * i; j < arrSize; j += i)
for(int j=i*i;j
请注意,i*i
是循环计数器j
的初始值。因此,j
大于i*i
的值都将被标记掉。我们从i*2
跳到i*i
的值在以前的迭代中已经被标记掉了。让我们考虑第一个t少数:
当i==2
时,我们划掉2的所有倍数(2、4、6、8等)。当i==3
时,如果我们开始j=3*2=6
时,我们将在达到9、12、15等之前再次划掉6。因为6是2的倍数,并且已经划掉了,我们可以直接跳到3*3==9
当我们到达i==5
时,如果我们从j==5*2==10
开始,那么我们将标记10,这是已经考虑过的,因为它是2的倍数,15是3的倍数,20也是2的倍数,在我们最终到达25之前,它不是任何小于5的倍数
时间复杂性是让人困惑的地方。我发现了这个符号O(n(logn)(loglogn))--那是什么?根据我的理解,我们有2个完整迭代和1个部分迭代,因此O(n^2*logn)
您的分析得出了正确的结果,该算法是O(n^2*logn)
。可以证明一个更严格的上界为O(n(logn)(loglogn))
。注意O(n(logn)(loglogn))
是O(n^2*logn)
的子集
为什么i*i比i*2更有效?它不跳过一些数字吗
不,这不是因为i
的较小倍数(例如,在您的情况下,在运行i=2
,i=3
等的循环时,会覆盖18、27等)
每个数字都可以表示为唯一的素数分解。如果i
是素数,则i
大于i
且小于i*i
的任何倍数都将是小于i
的一个或多个素数的倍数
讨厌的符号O(n(logn)(loglogn))
从
操作数为1/2+1/3+1/5+1/7…=n log log n
如果你计算位运算,因为你处理的是n以下的数字,它们大约有logn位,这就是logn的因子,给出O(n logn logn)位运算。 VLA不是C++中的好主意。大尺寸VLA完全是一个不同的问题。喜欢一个容器。在以前的迭代中已经消除了比 i>代码>的所有倍数的可能的重复。因此,<代码> i *i/c>是<>代码> i <代码>的最小倍数,但尚未被消除。(把从1到100的数字写在纸上,用手执行算法查看。)至于i*i
问题,它不会跳过任何内容,因为每个小于i^2
的数字要么是素数,要么是素数因子小于i
,因此在上一步中已经被标记。“根据我的理解,我们有2个完整迭代和1个部分迭代,因此O(n^2*logn)”复杂性很难计算,特别是在不常见的情况下,如何计算出O(n^2*logn)?
for (int j = i * i; j < arrSize; j += i)