如果仅取决于输入值而不取决于输入大小,如何确定Big-o复杂度?

时间:2019-02-07 17:36:51

标签: javascript time-complexity big-o complexity-theory

我刚刚看到了有关使用setTimeout进行排序的javascript代码,如图所示

var list = [2,  5, 10, 4, 8, 32]; 
var result = [];
list.forEach( n => setTimeout(() => result.push(n), n));

这很有趣,因为在js中setTimeout是异步的,因此如果您等待足够的时间,result将被排序为数组。它是确定性的,仅取决于数据的值,而不取决于输入的大小,因此我不知道如何确定这种方法的Big-O(时间复杂度)。

1 个答案:

答案 0 :(得分:3)

TLDR; 取决于您如何定义setTimeout()

的复杂性

在讨论算法复杂度时,我们必须回答以下问题:

  • 我的投入是什么?
  • 我的算法在其中运行的假设机器中的工作单元是什么?

在某些情况下,我们如何定义输入取决于算法在做什么以及我们如何定义工作单元。使用内置函数时,问题很复杂,因为我们必须定义这些函数的复杂度,因此我们可以考虑它们并计算算法的整体复杂度。

setTimeout()的复杂性是什么?这需要解释。我发现将setTimeout()的复杂度设为O(n)很有帮助,其中n是传递给函数的毫秒数。在这种情况下,我决定setTimeout()内部计算的每一毫秒代表一个工作单元。

鉴于setTimeout()的复杂度为O(n),我们现在必须确定它如何适合我们算法的其余部分。因为我们遍历list并为列表的每个成员调用setTimeout(),所以我们将n与另一个变量相乘,我们将其称为k来表示列表的大小

将所有内容放在一起,算法的复杂度 O(k * n) ,其中k是给定数字的长度,而n是其中的最大值列表。

这种复杂性有意义吗?让我们通过解释分析结果进行健全性检查:

  • 我们的算法需要更长的时间,因为我们给它更多的数字✓
  • 我们的算法需要更长的时间,因为我们给它更大的数字✓

请注意,得出此结论的关键是确定setTimeout()的复杂性。如果我们给它一个恒定的O(1)复杂性,我们的最终结果将是O(k),这是IMO的误导。


编辑:

对于所有输入,对setTimeout()对我们的复杂性的贡献的更正确的解释可能是O(n),其中n是给定列表的最大值,而不管多少次它被称为。

在原始帖子中,我假设setTimeout()将为列表中的每个项目运行n次,但是这种逻辑存在一些缺陷,因为setTimeout()在概念上“缓存”了先前的值,因此,如果使用setTimeout(30), setTimeout(50), and setTimeout(100)调用它,它将运行100个工作单元(而不是原始帖子中的180个工作单元)。

鉴于对setTimeout()的这种新的“缓存”解释,复杂度为 O(k + n),其中k是列表的长度,而{{ 1}}是列表中的最大值。

有趣的事实: 碰巧具有与Counting Sort相同的复杂度,后者的复杂度也是列表大小和最大列表值的函数