为什么不是每个算法都是O(1)?

7
如果我们有一个包含 n 个整数的随机数组,需要计算这些整数的总和。 声明:最佳算法可以在 O(n) 的时间内完成此任务。
但是,我认为我们可以在 O(1) 的时间内完成。为什么呢?
因为我们知道 n 肯定被锁定在某个字段中(因为它是 int 类型且 int 是有限的),这意味着我可以在不到 2,147,483,647 步内对所有元素求和。
5个回答

15
为什么不是每个算法都是O(1)?
因为当我们分析算法复杂度时,选择忽略具体计算机的限制(即假定资源是无限的)。
渐近复杂度为我们提供了关于复杂度增长的有用信息。仅仅因为硬件的限制而得出一个恒定的极限,并忽略如何到达该极限并不能给我们有价值的信息。
此外,在现实中,您所感知到的极限要高得多。计算机不仅限于表示最多2'147'483'647个整数值。使用复杂的数据结构,计算机可以表示任意大的数字-直到内存用尽......但是内存可以从磁盘流式传输。并且有数据中心轻松提供数百Tera Bytes的存储。
尽管说实话:如果我们允许任意长度的整数,则求和的复杂度比线性更差,因为甚至单个加法也具有线性复杂度。
一旦考虑到具体的硬件,选择在分析中使用具体的单位更有意义:程序在这种特定的硬件上对某些具体输入需要多少秒?找到答案的方法不是数学,而是具体的测量。

8

为什么不是每个算法都是O(1)?

简而言之:因为大O符号被用于量化算法,关注其随输入增加而表现的方式。

非正式地说,您可以将其视为人类发明的框架,以量化算法类别。如果这样的框架为每个算法产生O(1),那么它本身的目的就会失败,即量化算法类别。

更详细的回答

让我们首先澄清当前上下文中的大O符号是什么。从(source)中可以读到:

大O符号是一种数学符号,描述了函数在参数趋向于特定值或无穷大时的极限行为。 (...) 在计算机科学中,大O符号用于根据输入大小的增长方式对算法进行分类。

下面的陈述不准确:
但是,我声称我们可以在O(1)中完成这个任务。为什么?我们确定n被锁定在某个字段中(因为它是int且int是有限的),这意味着我可以在少于2,147,483,647步内对所有元素求和?
一个人不能简单地执行“O(2,147,483,647)”并声称“O(1)”,因为Big O符号不代表一个函数,而是一个具有特定渐近上界的函数集;正如从源代码中可以看出的那样:

大O符号根据函数的增长速度进行分类:相同增长速度的不同函数可以使用相同的O符号表示。

在计算机科学的时间复杂度和空间复杂度理论中,人们可以将 Big O 表示法视为对算法进行分类,以考虑它们分别涉及时间和空间的最坏情况。例如,O(n):

如果一个算法的时间/空间复杂度是 O(n),那么就可以说该算法需要线性时间/空间,或者说它的时间/空间复杂度为 O(n)。简单来说,这意味着运行时间/空间随输入规模最多呈线性增长(source)。

因此,该复杂度为 O(n),因为随着输入的增加,复杂度呈线性而不是常数增长。


5

承认,所有算法都具有复杂度O(1)的理论意义不大。

在复杂度理论中,N是一个无界变量,因此可以得到非平凡的渐进上界。

对于实际算法而言,渐进复杂度在N的中等值(远远小于最大int)范围内模拟确切复杂度是有用的。


在一些病态情况下(如最复杂的矩阵乘法算法),N必须超过int的容量,才能使渐进行为变得有益。


侧面备注:

我想起了一篇声称某个操作具有O(1)时间复杂度的论文。该操作涉及像素值的直方图,其范围确实是固定的。但这是一个具有误导性的技巧,因为隐藏的常数与8位图像成比例为256,与16位图像成比例为65536,使得该算法非常缓慢。声称O(H),其中H是箱子的数量,将更加信息丰富和诚实。


2
你可以选择你所感兴趣的运行时依赖,以及定义变量N。你可以这样说:

“由于计算机资源有限,因此我将这些限制视为常量因素,现在我的所有算法都是O(1)。”

然而,这种观点的使用受到了限制,因为我们希望使用复杂度来分类算法,以查看哪些算法表现更好,哪些表现更差,而将所有算法放入同一个桶中的分类并没有帮助。

1
整数在定义上是可数无限的。因此,您无法基于 n 证明终止。如果您将整数重新定义为可数数字的有界区间,则只有当 n 是这样的整数文字时,才能声明 O(1)。
在我看来,O-符号的有用部分是关于时间复杂度与输入的关系的信息。在我的输入受到限制的情况下,我只关注边界内的行为。在这种情况下,它是 O(n)。您可以声称 O(1),但这会剥夺它的信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接