为什么两个O(n)程序相同?常数很重要吗?



可能的重复:
复杂。为什么常数不重要?

我有一个关于代码/算法复杂性的简单问题。我很好地理解了基本的复杂性概念,例如关于输入的增长顺序,为什么O(n)比O(n^2)等更好,但是,我不确定Stonstants是否真的重要对我来说,他们应该应该考虑或谈论它们。您可以以相同的复杂性改进代码吗?假设我有一个具有一定顺序复杂性的代码,请说O(n)。假设此代码在10分钟内以某些输入运行。如果我重复两次代码,并且现在代码在20分钟内运行。尽管复杂性相同,但在10分钟内有20分钟的时间很大。这些事情是否重要,无论复杂性是否相同?如果不是,为什么?如果是,为什么?请解释。

在理论复杂性分析中,系数根本无关紧要。实际上,它们很重要。这就是为什么几乎每个人仍然使用(指数复杂性)单纯算法而不是(多项式复杂性)内部点算法来优化问题。

如果您正在进行算法分析并想知道O()行为,则常数是无关紧要的。如果您想知道哪个代码将在特定问题范围内更快地运行,那么一切都很重要。

我认为您正在混合真实的概念具有不同的性能示例的复杂性。根据复杂性,我们的意思是:如果n成长,处理步骤的顺序是什么。

说例如,您正在执行线性搜索,在这种情况下的订单为o(n)。这是什么意思是:如果n = 5,则需要5秒钟,然后n = 10,则需要10秒,即关系是线性的。

它没有区别,如果订单为o(5n),即您相同的搜索需要25秒n = 5,则在n = 10中,将需要50秒。我仍然可以说,它的o(n),即直接依赖。

同一示例与O(n^2)的排序算法。

在您的示例中,上述改进确实很重要,但它不会改变复杂性的顺序,即关系。如果我们可以将处理时间减少两次,这是一个很大的改进,因为n是一个很高的数字,例如。时间从20分钟减少到10分钟。如果您更改了算法以更改与n种成长的时间的关系,则O(n)也将更改:)

对于复杂性理论而言,它仅感兴趣 函数如何随着输入大小的增长而缩放。

常数不会影响功能作为输入大小的表现

根本成长

但是,如果您有兴趣实际运行某个部分 代码,您很可能对大型常数开销感兴趣,并且 该函数如何针对较小的输入尺寸执行。

复杂性理论与实践之间的差异。

这是这个问题的一个很好的答案。

复杂性。为什么常数不重要?

当然,如果您制作的算法是速度较慢的两倍,那么这很重要。关键是,我们关心算法在" N"方面的性能,因为" N"有可能变得很大。

让我们以一个实用的例子。假设您有n个项目的列表。您的算法一次遍历列表。那是订单n。如果它在列表上迭代两次,那可能需要更长的时间,并且较慢 - 如果不需要,您不应该这样做。

但是,长期以来,具有N^2算法的影响要比2*n算法更大。随着n越来越大,n^2和2*n之间的差异变得越来越大。

为了回答您的问题,是的,当程序运行的速度两倍时,这很重要。但是,如果呈指数较慢,那么重要。这就是为什么我们关心大哦。但是,对速度的任何改进显然都对您的程序有好处。

这是理论和实践之间的差异。有一些要考虑的要点:

  • 常数可能不清楚实际实施。您通常不能从给定的实现中确定那些常数。例如,让我们说您有两个针对同一问题的O(n)算法,但是一个需要2N操作,第二个操作仅需要n操作。一个人可能会假设具有N操作的操作运行速度更快,但情况并非如此。我们可能有2N操作,每个操作仅由于较高的缓存或管道使用等,每个操作只有1个周期,而其他算法可能会采用n个操作,每个操作每个周期为4个周期。因此,具有更多操作的算法可能仍然更快。在另一个硬件上,这看起来可能会大不相同。因此,除非您知道确切的硬件,否则理论分析是一个很好的指南。在实际硬件上,相互作用通常是如此复杂,只有基准测试才能给您一个很好的提示。

  • 对于实时系统,情况再次有很大不同。这里通常对最坏情况的执行时间(WCET)感兴趣,该执行时间是指算法可能需要的实际时间。在这种情况下,常数确实很重要。但是,在这种情况下,问题大小也已知(通常是来自几个传感器的一组输入),因此分析大大不同。

  • 硬件的影响可能会变得如此之大,以至于理论上看起来更糟糕的算法实际上可能胜过看起来更好的算法,至少对于所有相关问题大小而言。对于使用树(理论上通常更好)与使用平坦阵列结构(理论上通常更糟)的算法的算法通常是这种情况。通常,平面阵列更好,因为它可以更有效地缓存。有时,可以使用两全其美的最好的,例如,在将堆作为数组实现时(这几乎总是胜过分类的树)。

将O(n)与O(n^2)进行比较时,随着n的成长常数将开始变得无关紧要。即使常数很大,也应该很明显。

未提及常数的原因是复杂性的顺序更为重要。一旦您知道算法是线性时间,您就可以在研究详细信息的同时自己检查斜率。

当您有两个程序时,o(n)常数在决定哪个更好的过程中很重要。然后,您必须更详细地分析算法。

最新更新