如何解决素数函数的Big-O表示法?

时间:2014-04-29 10:23:04

标签: c# algorithm big-o

我想了解Big-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)) 
           Console.WriteLine("{0} is prime", i);
     }

现在我得到的是,我认为if子句被认为是常数O(1)并且在计算此算法时没有考虑到这一点?如果我正确理解了一个for循环

for(i = 0; i < 100; i++)

因为它是一个线性函数是O(n)和一个不依赖于周围循环变量的嵌套循环

for(i = 0; i < 100; i++)
    for(j = 0; j < 100; j++)

是O(n ^ 2)?但是我如何计算一个函数,例如第二个循环依赖于第一个循环并创建非线性函数的顶部函数?

Picture of my data points

我找到了一个名为

的linearithmic定义
  

线性算法可以扩展到巨大的问题。每当N加倍时,   比双打更多(但不多)的运行时间。

虽然这似乎是对这段代码片段如何运行的一个很好的描述,这意味着它是O(N Log [n]),如果是这样,我怎么能计算出来?

3 个答案:

答案 0 :(得分:6)

@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)The harmonic number)位于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))。根据{{​​3}},平方根的总和在O(n*sqrt(n)),比O(nlogn)“更差”。

需要注意的事项:

  1. 第一笔金额最高为sqrt(i),因为这是j > (i / j)的点。
  2. 每个(j-1)/j的第一笔总和为j,因为平均有j个元素中的一个进入休息时间(1/3的元素可以分为3,1 / 4 by 4,...)这使我们(j-1)/j不是 - 这是我们所期望的工作。
  3. 对于任何常量O(log(sqrt(n)) = O(1/2*log(n),等级O(log(n^k))=O(k*log(n))=O(log(n))来自k。 (在你的情况下,k = 1/2)

答案 1 :(得分:1)

分析你的算法,我想出了以下内容:

  • 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位于[81, 99]区间时,内部循环会重复八次。 我不得不去超过100的范围来验证上述情况。
  • i位于[100, 120]区间时,内部循环会重复九次

取决于i's值的间隔可以表示如下:

[i^2, i * (i + 2)]

因此,我们可以这样做:

enter image description here

经验验证:

enter image description here

使用有用的WolframAlpha链接:

http://www.wolframalpha.com/input/?i=sum[+floor%28+i^%281%2F2%29%29+-+1+]+with+i+from+2+to+99.

在形式上,我们可以说明以下内容:

enter image description here

答案 2 :(得分:0)

我看了你的代码 - 而且没有n。代码不依赖于任何n。它将始终以完全相同的固定时间运行。你可以计算它需要多长时间,但它始终是相同的,恒定的,时间。如上所述,以“for(i = 2; i&lt; 100; ++ i)”开头的代码在O(1)中运行。

所以将第一行改为

for (i = 2; i < n; ++i)

现在我们的代码实际上取决于n。内循环最多运行sqrt(i)次迭代,小于sqrt(n)。外循环运行大约n次迭代。因此执行时间最多为O(n sqrt(n))= O(n ^ 1.5)。

实际上,它会跑得更快。它通常不会达到sqrt(i),但只有在找到i的除数之前。一半数字可被2整除(一次迭代)。其余三分之一可被3整除(两次迭代)。其余五分之一可被5整除(四次迭代)。关于n / nn个数是具有sqrt(n)次迭代的素数。关于n / ln n个数是两个素数的乘积&gt; 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)时间控制,并且显示结果的非常大的常数因子直到n变得非常大。