IF 如何影响复杂性?
Posted
技术标签:
【中文标题】IF 如何影响复杂性?【英文标题】:how does IF affect complexity? 【发布时间】:2013-05-30 20:33:14 【问题描述】:假设我们有一个包含 1.000.000 个元素的数组,我们遍历所有元素以检查一些简单的内容,例如第一个字符是否为“A”。根据我(很少)的理解,复杂性将是O(n)
,并且需要一些 X 时间。如果我添加另一个 IF(不是 else if)来检查,假设最后一个字符是“G”,它将如何改变复杂性?它会使复杂性和时间加倍吗?喜欢O(2n)
和2X
?
我想避免考虑不同命令必须进行的计算次数。例如,我知道 Len() 比简单的 char 比较需要更多的计算才能给我们结果,但是假设 IF 中使用的命令将具有(几乎)相同的复杂性。
【问题讨论】:
我投票结束这个问题,因为它不是关于开发软件的实践,而是关于理论。 Theory 有自己的 Stack Exchange 站点,地址为 Computer Science。 【参考方案1】:O(2n) = O(n)
。概括,O(kn) = O(n)
,k
是一个常数。当然,使用两个 IF 可能需要两倍的时间,但执行时间仍然是输入大小的线性函数。
编辑:Here 和 Here 是对不太面向数学的大 O 表示法的解释和示例
【讨论】:
非常感谢。我没能理解复杂性和时间之间的关系。 很好的链接,我以为我以前知道大O,现在我真的知道了!【参考方案2】:渐近复杂度(这是 big-O 使用的)不依赖于常数因子,更具体地说,您可以在函数中添加/删除 any 常数因子,它将保持等效(即 O(2n) = O(n))。
假设一个 if 语句花费的时间是固定的,它只会给复杂性增加一个固定的因素。
“恒定的时间”是指:
给定元素的 if 语句所花费的时间不取决于数组中还有多少其他元素 所以基本上如果它不调用以某种方式或类似方式查看数组中其他元素的函数 任何非函数调用 if 语句都可能没问题(除非它包含通过数组的语句,某些语言允许这样做)因此,为每个元素调用的 2 个(恒定时间)if 语句将是 O(2n),但这等于 O(n)(嗯,它可能不是真正的 2n,更多内容在附加注意)。
有关更多详细信息和更正式的定义,请参阅Wikipedia。
注意:除了不依赖于常数因子外,它也不依赖于渐近较小的项(无论 n 有多大,这些项都保持较小),例如O(n) = O(n + sqrt(n))。而大 O 只是一个上限,所以说它是 O(n9999) 也是正确的(尽管说在测试/考试中可能会给你 0 分)。
附加说明:不忽略常数因素时的问题是 - 什么归类为工作单元?这里没有标准定义。一种方法是使用耗时最长的操作,但确定这一点可能并不总是直截了当,也不总是特别准确,您也无法笼统地比较不同算法的复杂性。
【讨论】:
【参考方案3】:关于时间复杂度的一些要点:
-
Theta notation - 精确界限,因此如果我们正在分析的一段代码包含条件 if/else 并且任何部分都有更多的代码,这些代码会根据输入大小而增长,则无法获得精确界限,因为可能会采用任何一个分支,并且在这种情况下不建议使用 Theta 表示法。另一方面,如果两个分支都解析为恒定时间码,那么在这种情况下可以使用 Theta 表示法。
Big O notation - 上限,因此如果代码有条件,其中任何一个条件分支都可能随着输入大小 n 增长,那么我们假设最大值或上限来计算代码的时间消耗,因此假设我们采用具有最大时间消耗的路径,我们将 Big O 用于此类条件。因此,在摊销分析中可以将具有较短时间的路径假定为 O(1)(包括我们假设该路径没有可能随着输入大小而增长的递归这一事实)并计算最长路径的时间复杂度 Big O .
Big Omega notation - 下限,这是一段代码无论输入如何都能占用的最小保证时间。对于代码所花费的时间不会根据输入大小 n 增长但会消耗大量时间 k 的情况很有用。在这些情况下,我们可以使用下限分析。
注意:所有这些符号都不取决于输入是最佳/平均/最差,所有这些都可以应用于任何一段代码。
所以如上所述,Big O 不关心诸如 k 之类的常数因子,只看到时间如何随着 n 的增长而增加,在这种情况下,这里是 O(kn) = O(n) 线性。
PS:这篇文章是关于大O与分期分析的条件评估标准的关系。
【讨论】:
【参考方案4】:这与我今天发布的一个问题有关。
在您的示例中,这取决于您是否可以从第一个元素跳转到最后一个元素,如果不能,则还取决于每个条目的平均长度。
如果您在遍历数组时必须阅读每个完整条目以评估您的两个 if 语句,那么您的订单将是 O(1,000,000xN),其中 N 是每个条目的平均长度。如果 N 是可变的,那么它将影响顺序。一个例子是标准乘法,我们对一个长度为 Log(N) 的条目执行 Log(N) 加法,因此顺序为 O(Log^2(N)) 或者如果您更喜欢 O((Log(N) )^2)。
另一方面,如果您可以只检查第一个和最后一个字符,则 N = 2 并且是常数,因此可以忽略。
这是一个重要的点,你必须小心,因为你如何决定你的倍数是否可以被忽略。例如,假设我们正在对 Log(N/100) 数进行 Log(N) 加法。现在仅仅因为 Log(N/100) 是较小的术语并不意味着我们可以忽略它。如果是可变的,乘数是不能忽略的。
【讨论】:
-1 常数因素对复杂性没有影响。它们可能会影响实际观察到的运行时性能(并且严重影响),但这是另一回事。 正如我试图说明的那样,这取决于您的阅读作为一个恒定因素。例如,如果您进行 N 次迭代并且您的“常数”因子是 N,那么您不能只是忽略 N 作为常数。如果是这种情况,乘法将是一个 Log(N) 运算,而不是一个 Log(N^2) 运算。与您的迭代次数相比,我说的常数必须很小。我应该补充一点,在这种情况下 N 不是一个常数,因为它取决于我所说的数组元素的平均大小,这是另一个变量。你可以设置一个固定的上限,这就是你在最坏的情况下所做的事情 我认为我们正在交叉发布。你错过了我的编辑? N 是另一个变量,它不是一个常数,我没有在我的原始帖子中称它为一个,我只是在这里做的,因为这就是你提到它的方式。我们称它为乘法器。关键是,只有与乘数相比,乘数较小时,才能忽略乘数。哎呀,我看到最后我确实称它为常数。不是我的意思。我的意思是乘数,但是当我编辑并添加最后一个注释时,我犯了一个错误。 我想我现在明白你的意思了,但你的措辞仍然不正确。如果 N 是一个常数,无论它有多大,都可以忽略它的复杂性。如果 N 不是常数,但取决于输入的大小,则不能忽略。即使该项与复杂性的主要项相比很小,也是如此。对于大 N,即使 log(N) 项也会向无穷大增长,所以你不能忽略它!小和大在这里是错误的类别。这是关于常数或非常数。 是的,我明白你所说的错误措辞是什么意思,只要乘数是可变的,它就不能被忽略,尽管我担心这也会让人们感到困惑,因为我们可以忽略一个小变量而不是它们影响显着的复杂性,例如如果我们添加另一个我们知道会相对较小的变量。例如 O(Log(N^2) + Log(N)) = O(Log(N^2))。以上是关于IF 如何影响复杂性?的主要内容,如果未能解决你的问题,请参考以下文章