当你有代码时:
for(int i = 0; i<N; i++)
{
array[i] += N
}
每次循环迭代时,不是比较变量i和N.对于那个问题,不是每次循环迭代时都加1吗?
那么,循环的每次迭代不是这3个操作吗?
为什么我们通常忽略这些操作并说这段代码是O(n)?它与这些操作如何使用CPU有关吗?
答案 0 :(得分:12)
Big-O表示法不处理操作的实际成本,但是成本如何随着问题的大小而增加。在这种情况下,O(n)
并不意味着费用为n
,而是费用与问题的大小呈线性增长。无论100个元素的成本是多少,它都会增加一倍,200倍和1000倍。同样,O(n^2)
意味着成本增加二次,所以如果问题的大小增加一倍如果规模增加十倍,则运营成本翻两番,成本增长百倍。
常数在这里并不重要,它们通常被考虑在内。此外,在许多分析中,成本甚至没有表示实际时间或内存成本,而是其他操作的成本。例如,无论密钥类型如何,std::map::find
函数都被称为O( log N )
。原因完全相同:O( log N )
表示无论在具有N
元素的地图中查找的成本是多少,它都会以对数方式增长。
对于一个激励性的例子,考虑一个相当荒谬的问题:从完整的书籍内容和两个实现中找到一本书的作者。在第一个实现中,您使用std::map<std::string, std::string>
,其中第一个std::string
是书的内容,第二个是作者的名称。第二个实现执行将书籍内容散列为整数并将其存储到无序std::vector< std::pair<int, std::string> >
中,int
是散列,std::string
是作者姓名(假设没有散列)碰撞)。在地图中查找图书作者的费用为O( log N )
,在向量中查找作者的费用为O( N )
,这更糟糕。但是,这些成本隐藏了比较的复杂性,比较地图中的整本书内容的成本可能巨大与比较哈希的成本相比,直到单一比较的点一本书的内容可能比矢量案例中所需的所有比较都要贵。
Big-O表示法仅处理成本随问题大小增长的方式,并隐藏每项操作的实际成本。在分析算法的复杂性时,单个成本被忽略,但您仍应注意它们,因为Big-O表示法并不能说明整个故事以及运行算法的实际成本将导致您在分析中忽略的那些不变成本。
答案 1 :(得分:6)
Big-O表示法可以删除所有常数因子。调用一次迭代c
的比较,加法和所有其他开销。在删除常数因子时,总运行时间为cn
和O(cn) = O(n)
。
此数学技巧用于比较将在大型数据集上工作的函数。时间复杂度为O(n^2)
的算法可能比小数据集上O(n)
的算法快得多(如果后者的常数因子很大),但无论算法如何,小数据集通常都会快速处理。有趣的是,当数据集增长时会发生什么 - 搜索十亿条记录需要十秒钟,还是需要几年?这很受时间复杂性的影响。
答案 2 :(得分:6)
Big-O [*]的定义:
对于两个函数f
和g
,f(n)
是O(g(n))
当且仅当存在数字M
,c
时, :
for all n > M, |f(n)| <= c * |g(n)|
(其中|x|
是x
)的绝对值。
所以从这个定义中很容易看出函数3*n
是O(n)
:只需要c = 3
和任何肯定的M
即可。
关于“增长率”的解释几乎是华夫饼(实际上,它们是上述定义的动机),但它们可能有助于形成关于Big-O如何工作的直观概念。
为什么要允许一个常数因子?为什么不在f
O(g)
|f(x)| < |g(x)|
时定义n > M
为n
?有几个原因 - 首先是因为“增长率”华夫饼干/动机:我们用big-O表示法真正说的是当你加倍O(n)
,三倍等等时会发生什么。其次是因为这个想法一项“行动”并不明确。将1添加到整数不会花费与比较或跳转相同的时间量。它甚至不一定需要相同数量的CPU指令。那么你要测量什么呢?秒? CPU周期?什么CPU,以什么速度运行,具有什么总线带宽?如果算法A在x86上的速度稍微快一点,而算法B在ARM上的速度稍微快一点怎么办?那么他们中任何一个的时间是Big-O(另一个的时间)?
对于抽象分析,我们需要比较不以任何特定硬件为根的算法的方法,而Big-O就是这些工具之一。
因此,它与算法的大O复杂度无关,无论它是每循环执行三次恒定时间操作,还是一百万次。它们仍会贡献c
时间,只需选择足够大的log(n)
。
如果您为每个循环执行n
次操作(循环O(n)
次),那么您不再是c
,因为对于任何log(n) > c
,最终n
足够大M
。因此,不存在满足条件的任何c
和n * log n
。 O(n)
不是{{1}}。
[*]因为它适用于算法的复杂性 - 当接近无穷大以外的极限时也会使用Big-O,但我们并不关心。
答案 3 :(得分:0)
我们说它与n成正比,因为n接近无穷大。所以n *(4次操作),我不知道它们对处理器的处理时间与n成正比。
答案 4 :(得分:0)
您是否具有等于2或2 ^ 10的常数因子并不重要。最重要的是'与增长的n'相比,执行时间将如何增长。由于代码将由编译器优化,因此常数因素也会下降。您无法确定优化后c
是否仍然相等。
我建议您熟悉www.coursera.org Algorithms: Design and Analysis, Part I
在线课程。有几个(简短的)关于丢弃常数因子和大O符号的讲座。