Wat*_* v2 7 c# algorithm big-o computer-science time-complexity
我使用的是C#语法,但这个问题并不仅限于C#.
例1
public static long Do(long n)
{
var sqrt = (long)Math.Sqrt(n);
for(long i = 0; i < sqrt; i++)
// do something
return result;
}
Run Code Online (Sandbox Code Playgroud)
这仍然是线性时间,即使在最坏的情况下,我们只做平方根时间的操作n
,这只是一小部分n
?
例2
您将如何对下面算法的时间复杂度进行分类?
public static long Do(long n)
{
while (n > 1)
{
n = (long)Math.Sqrt(n);
// do something
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
在最坏的情况下,这会被称为在对数时间内完成的操作,即使我们再一次不仅仅是将迭代次数减半,而是将它们减少一个数量级,而不仅仅是一半.
第一个代码片段仅包含一个循环以及该循环之外的恒定数量的操作。如果这个循环迭代了k
很多次,而每次迭代都需要t
时间,那么它的复杂度就是O(kt)
。这里,k
等于sqrt(n)
,这意味着如果循环不包含非常量时间操作(例如,如果它不包含嵌套循环或循环函数等),则该片段的时间复杂度等于O(sqrt(n))
也写为O(\xe2\x88\x9an)
。
事实上,这里有一个循环并不意味着任何复杂性。例如,以下代码具有两个嵌套循环,具有线性复杂度:
\n\nint j = 0;\nfor (int i = 0; i < n; ++i)\n{\n for (; j < n; ++j)\n {\n // A loop with constant-time operations and eventual breaks\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n在这个例子中,i
从0
到n
,因此我们花O(n)
时间增加i
。类似地,j
从0
到n
,我们进行变量O(n)
增量j
以及O(n)
内部循环体的迭代。由于这段代码中没有其他操作,因此总复杂度为O(n) + O(n) + O(n) = O(n)
。
为了处理第二个例子,我以递归方式重写它:
\n\nint Do(int n)\n{\n // Do something with constant-time compexity\n return n > 1 ? Do(sqrt(n)) : result;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n我们将此示例的时间复杂度称为T(n)
。我们可以看到,T(n) = 1 + T(sqrt(n))
该函数第一部分的计算时间(恒定)被视为时间单位。求解这个递归方程给出我们T(n) = log log n
(这里的对数是二进制的)。的确,1 + log log(sqrt(n)) = 1 + log ((log n) / 2) = 1 + log log n - 1 = log log n
。对于渐近表达式,使用哪个对数底并不重要,因为log_a x = log_a b * log_b x = O(log_b x)
,这就是通常省略对数底的原因。
因此,复杂性是:O(\xe2\x88\x9an)
和O(log log n)
。
UP:为了非严格地估计你的复杂性,可以使用 Excel 或任何其他软件工具进行计算。您只需构建一个不同值的操作数表n
,并尝试猜测复杂性规则。例如,对于问题中的代码片段#2:
\n\nN 操作日志 n 日志 日志 n \n1 1 0 - \n2 2 1 0\n4 3 2 1\n16 4 4 2\n256 5 8 3\n65536 6 16 4\n\n\n\n
正确答案通常从表格中显而易见
\n 归档时间: |
|
查看次数: |
714 次 |
最近记录: |