我刚刚看到了有关使用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(时间复杂度)。
答案 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相同的复杂度,后者的复杂度也是列表大小和最大列表值的函数