如果仅取决于输入值而不是输入大小,如何确定 Big-o 复杂性?
How to determine Big-o complexity if it only depends on values of input rather than input size?
我刚刚看到 javascript 关于使用 setTimeout
进行排序的代码,如图
var list = [2, 5, 10, 4, 8, 32];
var result = [];
list.forEach( n => setTimeout(() => result.push(n), n));
这很有趣,因为在 js 中 setTimeout
是异步的,所以如果您等待足够的时间,result
将排序数组。它是确定性的,仅取决于数据值而不是输入的大小,所以我不知道如何确定这种方法的 Big-O(时间复杂度)。
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
是给定列表的最大值,无论如何多次被调用。
在原来的 post 中,我假设 setTimeout()
会对列表中的每个项目 运行 n
次,但是这个逻辑有点缺陷,因为setTimeout()
概念上 "caches" 以前的值,所以如果用 setTimeout(30), setTimeout(50), and setTimeout(100)
调用它,它将 运行 100 个工作单位(而不是 180 个工作单位,情况是在原来的 post).
给定 setTimeout()
的新 "cached" 解释,复杂度为 O(k + n),其中 k
是长度列表中的最大值,n
是列表中的最大值。
有趣的事实:
这恰好具有与 Counting Sort 相同的复杂度,其复杂度也是列表大小和最大列表值的函数
我刚刚看到 javascript 关于使用 setTimeout
进行排序的代码,如图
var list = [2, 5, 10, 4, 8, 32];
var result = [];
list.forEach( n => setTimeout(() => result.push(n), n));
这很有趣,因为在 js 中 setTimeout
是异步的,所以如果您等待足够的时间,result
将排序数组。它是确定性的,仅取决于数据值而不是输入的大小,所以我不知道如何确定这种方法的 Big-O(时间复杂度)。
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
是给定列表的最大值,无论如何多次被调用。
在原来的 post 中,我假设 setTimeout()
会对列表中的每个项目 运行 n
次,但是这个逻辑有点缺陷,因为setTimeout()
概念上 "caches" 以前的值,所以如果用 setTimeout(30), setTimeout(50), and setTimeout(100)
调用它,它将 运行 100 个工作单位(而不是 180 个工作单位,情况是在原来的 post).
给定 setTimeout()
的新 "cached" 解释,复杂度为 O(k + n),其中 k
是长度列表中的最大值,n
是列表中的最大值。
有趣的事实: 这恰好具有与 Counting Sort 相同的复杂度,其复杂度也是列表大小和最大列表值的函数