C# 如何求解素数函数的大O表示法?
我正在努力理解大O符号。很抱歉,如果我问了一些太明显的问题,但我似乎无法理解这一点 我有下面的C#代码函数,我正试图为它计算Big-O符号C# 如何求解素数函数的大O表示法?,c#,algorithm,big-o,C#,Algorithm,Big O,我正在努力理解大O符号。很抱歉,如果我问了一些太明显的问题,但我似乎无法理解这一点 我有下面的C#代码函数,我正试图为它计算Big-O符号 for (i = 2; i < 100; i++) { for (j = 2; j <= (i / j); j++) if ((i % j) == 0) break; // if factor found, not prime if (j > (i / j))
for (i = 2; i < 100; i++)
{
for (j = 2; j <= (i / j); j++)
if ((i % j) == 0) break; // if factor found, not prime
if (j > (i / j))
Console.WriteLine("{0} is prime", i);
}
因为它是一个线性函数,所以它是O(n)和一个嵌套循环,不依赖于周围循环中的变量
for(i = 0; i < 100; i++)
for(j = 0; j < 100; j++)
(i=0;i<100;i++)的
对于(j=0;j<100;j++)
是O(n^2)?但是我如何计算一个函数,比如上面的函数,其中第二个循环依赖于第一个循环,并创建一个非线性函数
我找到了线性数学的一个定义
线性算法可扩展到大型问题。每当N翻倍,
运行时间增加了一倍(但不多)
虽然这似乎是对这个代码段如何运行的一个很好的描述,但这是否意味着它是O(N Log[N]),如果是,我该如何计算呢?@Jon很接近,但他的分析有点错误,并且算法的真正复杂性是
O(N*sqrt(N))
这是基于这样一个事实,即对于每个编号i
,您应该在内部循环中执行的预期“工作”数量为:
1/2 + 2/3 + 3/4 + ... + (sqrt(i)-1)/sqrt(i) =
= 1-1/2 + 1-1/3 + ... + 1-1/sqrt(i)
= sqrt(i) - (1/2 + 1/3 + ... + 1/sqrt(i)
= sqrt(i) - H_sqrt(i)
由于H_sqrt(i)
()是在O(log(sqrt(i))=O(1/2*log(i)
中,我们可以得出这样的结论:对于每个素数计算,复杂性是O(sqrt(i)-log(i))=O(sqrt(i))
由于这是每个i
重复进行的,因此问题的总复杂性是O(sqrt(2)+sqrt(3)+…+sqrt(n))
。根据,平方根的和是O(n*sqrt(n))
,比O(nlogn)
更“糟糕”
注意事项:
j>(i/j)
的点j
,第一个和是(j-1)/j
,因为平均每j
个元素中有一个进入了中断状态(1/3的元素可以除以3,1/4除以4,…),这就剩下了我们没有的(j-1)/j
,这是我们所期望的工作k
的等式O(log(sqrt(n))=O(1/2*log(n)
来自O(log(n^k))=O(k*log(n))=O(log(n))
(在您的例子中,k=1/2)通过分析您的算法,我得出以下结论:
- 当
处于区间i
时,内部循环不会迭代[2,3]
- 当
处于区间i
时,内部循环会迭代一次[4,8]
- 当
处于区间i
时,内部循环会迭代两次[9,15]
- 当
处于区间i
时,内部循环会迭代三次[16,24]
- 当
处于区间i
时,内部循环会迭代四次[25,35]
- 当
在区间i
中时,内部循环会迭代五次[36,48]
- 当
在区间i
中时,内部循环会迭代六次[49,63]
- 当
在i
间隔内时,内部循环会迭代七次[64,80]
- 当
在i
间隔内时,内部循环会迭代八次。 我必须去一个大于100的范围来验证上述内容[81,99]
- 当
在i
间隔内时,内部循环会迭代九次[100120]
i的
值的间隔可以如下表示:
[i^2, i * (i + 2)]
因此,我们可以这样做:
经验验证:
通过一个有用的WolframAlpha链接:
http://www.wolframalpha.com/input/?i=sum[+floor%28+i^%281%2F2%29%29+-+1+]+with+i+from+2+to+99.
我们可以正式声明如下:
我查看了您的代码-没有n。代码不依赖于任何n。它将始终在完全相同的固定时间内运行。您可以计算它需要多长时间,但它始终是相同的常量时间。如前所述,以“for(I=2;I<100;++I)”开头的代码在O(1)中运行 因此,将第一行更改为
for (i = 2; i < n; ++i)
(i=2;i
现在我们有了实际上依赖于n的代码。内部循环最多运行sqrt(i)次迭代,比sqrt(n)次要少。外部循环大约运行n次迭代。所以执行时间最多为O(n sqrt(n))=O(n^1.5)
实际上,它会运行得更快。它通常不会运行到sqrt(i),但只有在找到i的除数之前才会运行。一半的数字可以被2整除(一次迭代)。剩下的三分之一可以被3整除(两次迭代)。剩下的五分之一可以被5整除(四次迭代)。大约n/ln n个数字是带有sqrt(n)的素数迭代次数。大约n/ln更多的数字是两个素数>n^(1/3)与最多sqrt(n)次迭代的乘积。其余的少于n^(1/3)次迭代
所以代码实际上是在O(n^1.5/ln n)中运行的。您可以通过使用一个素数表来改进这一点,直到sqrt(n),然后将其减少到O(n^1.5/ln^2 n)
但是在实践中,你可以打赌Console.WriteLine()比检查一个数字是否为素数花费的时间要长得多。如果你坚持列出所有素数,那么你的算法将被O(n/ln)控制用一个非常大的常数因子来显示结果,直到n变得非常大。次要问题-你是如何得到那张图的?仅供参考,我认为这个问题更适合。该网站是为更多的理论编程问题而设计的,而StackOverflow是为解决编程问题而设计的。与任何网站一样,请确保阅读发帖指南,熟悉需要回答的问题。@JLRishe-请不要添加这样的评论。如果您认为该问题应该
for (i = 2; i < n; ++i)