大哦表示法没有提及常数值


13

我是一名程序员,刚刚开始阅读算法。我对Bog Oh,Big Omega和Big Theta等符号并不完全相信。原因是根据Big Oh的定义,它指出应该存在一个函数g(x),使其始终大于或等于f(x)。对于n> n0的所有值,f(x)<= cn。

为什么我们在定义中不提及常数值?例如,假设一个函数6n + 4,我们将其表示为O(n)。但是,定义对于所有常数值都适用并不合适。仅当c> = 10且n> = 1时,这才适用。对于小于6的c值,n0的值将增加。那么,为什么不将常量值作为定义的一部分呢?


4
您打算如何精确表示常数值?
丹尼尔·B

1
如果将n绑定,则终止函数为O(1)。
布赖恩

Answers:


23

有多种原因,但最重要的原因可能是常量是算法实现的函数,而不是算法本身。不管算法的实现如何,算法的顺序对于比较算法都是有用的。

如果以C或Python或Scala或Postscript实现,则快速排序的实际运行时间通常会发生变化。气泡排序同样适用-运行时会根据实现情况而有很大不同。

但是,不变的事实是,在所有其他条件相同的情况下,无论哪种语言或机器,随着数据集的增大,运行冒泡排序所需的时间将比运行快速排序所需的时间更快。假设合理正确的实施方式,则使用它们。这个简单的事实使您可以在没有具体细节的情况下对算法本身进行智能推断。

算法的顺序过滤掉了因素,这些因素在实际的实际测量中很重要,但在摘要中比较算法时往往只是噪音。


22

O(n)和其他顺序表示法(通常)与小值函数的行为无关。它关心的是函数对于非常大的值的行为,即当n趋于无穷大时的极限。

常数在技术上很重要,但是通常在n足够大时将其抽象掉,c的值完全不相关。如果c的值很重要,我们可以将其包括在分析中,但除非所比较的函数具有非常大的常数因子,或者如果效率是特别重要的问题,则通常不会。


3
例如,建造金字塔为O(n),对金字塔进行图片排序为O(n log n)-在某些时候,您可能有足够的金字塔,与对新金字塔进行排序相比,对金字塔进行排序需要更长的时间!但仅适用于大量金字塔!
马丁·贝克特

很好的答案,但是对于给定的N,以及通常属于同一“复杂度”的两个算法,准确地执行OP所建议的并至少包括相对系数是有好处的。线性算法的每个元素的指令数量是另一个元素的两倍,可以称为* O *(2N)到第二个算法的* O *(N)来显示相对差异,因为对于任何N,第一个算法将始终是两倍秒的执行时间;但是,当与不同复杂度族的函数(例如* O *(NlogN))进行比较时,系数并不重要。
KeithS 2012年

10

按照定义 的大O表示法指出:大O表示法建立在这样的直觉上:对于n'和n'右边的所有值n,f(n)的值等于或小于cg(n)。 当您使用高价值(可变)因子(例如n平方或n立方)时,常量也无关紧要,因为它们只是常量,而不是变化的数量,而变化的数量可能会与这些因子一样大。 下面给出的是Big-O符号的图表。
For a given function g(n), we denote by O(g(n)) the set of functions:
O(g(n)) = {f(n): there exist positive constants c and n' such that 0<=f(n)<=c.g(n) for all n > n'}




在此处输入图片说明

这种表示法的本质在于事实“ how lower is f(n) from c.g(n) and not when it starts becoming lower”。


在那种情况下,对于每个O(n)也是n的大theta,因为根据定义,对于某个常数,它将是一个下界,而对于某些常数,则是一个上限。例如6n + 4也是一个大theta(n),因为当c小于10时,它始终是下界。当c大于10时,它是一个上限。那么我们可以说对于任何给定的Big Oh表示法也是Big theta吗?
Pradeep 2012年

1
您反过来说:“大Theta意味着大哦”。Big-Oh可以用Big-Theta代替,以渐近地紧定界限。
Vaibhav Agarwal

9

在算法分析中,增长顺序是关键的抽象概念,它给出了运行时间随输入大小的变化而变化的速率。假设某个算法有运行时间f(n) = 2n + 3。现在我们插入一些输入大小,

n = 10: 2 * 10 + 3 = 23

n = 100: 2 * 100 + 3 = 203

n = 10000: 2 * 10000 + 3 = 20003

n = 1000000: 2 * 1000000 + 3 = 2000003

n = 100000000 : 2 * 100000000 + 3 = 200000003

可以看出,增长顺序主要由变量决定n。常数2和3不太重要,并且随着输入大小的增加,它们在确定常数时变得不再重要。这就是为什么在算法分析中,为了支持确定函数增长顺序的变量而对常量进行补偿的原因。


1

Big-Oh表示法的整个概念专门用于忽略常量,并提供描述算法运行时的函数的最重要部分。

暂时忘记正式定义。哪个功能最差(增长速度更快),n^2 - 5000或者5000 n + 60000?对于n小于5000周围比,线性函数是更大(且因此更差)。除此之外(精确值5013?),二次方程更大。

因为有更多(多一些)大于5000的正数小于少于0.5的正数,所以通常我们将二次函数设为“更大”(更差)的函数。顺序符号(Big-Oh等)强制执行该操作(您可以始终使用这些定义消除加法和乘法常数)。

当然,事情并不总是那么简单。有时您确实想知道那些常数。插入排序或冒泡排序哪个更好?两者都是O(n^2)。但是一个真的比另一个更好。通过更精细的分析,您可以得到您想知道的常数。计算Big-Oh函数通常比更精确的函数容易得多。

Big-Oh忽略了这些常量以简化并简化最重要的比较。我们之所以喜欢这种表示法,是因为通常我们希望知道(几乎不相关的)常量。


1

(由于这是更长的答案,请阅读粗体以获取摘要

让我们以您的示例为例,并逐步讲解它,了解我们正在做的事情的目的。我们从您的功能开始,并找到它的Big Oh符号的目标:

f(n) = 6n+4

首先,O(g(n))我们尝试寻找的Big Oh符号f(n)。根据Big Oh的定义,我们需要找到一个简化的变量,其中存在一些常数对于大于的所有常数都是正确的 g(n)cn0c*g(n) >= f(n)nn0

首先,让我们选择g(n) = 6n + 4O(6n+4)在Big Oh中会产生)。在这种情况下,我们看到,c = 1和任何价值n0将满足我们的大哦定义的数学要求,因为g(n)总是等于f(n)

c*g(n)      >=  f(n)    
1*(6n + 4)  >=  6n + 4    //True for all n's, so we don't need to pick an n0

至此,我们已经满足了数学要求。 如果我们在O(6n+4)这里停下来,很显然,这没有什么比编写更有用的了f(n),因此它将错过Big Oh符号的真正目的:了解算法的一般时间复杂性! 因此,让我们继续下一步:简化。

首先,我们可以简化的出6n如此大的哦O(4)?没有! (如果读者不明白为什么要这么做)

其次,我们可以简化一下4大哦O(6n)吗?是! 在这种情况下g(n) = 6n,因此:

c*g(n)    >=  f(n)
c*6n      >=  6n + 4     

在这一点上,让我们选择,c = 2因为对于的每个增量,左侧将比右侧(增加6)更快(增加12)n

2*6n      >=  6n + 4

现在我们需要找到一个正数n0,对于所有n大于的值,上述方程式均成立。由于我们已经知道左侧的增长比右侧的增长快,因此我们所要做的就是找到一个积极的解决方案。因此,由于n0 = 2上述成立,因此我们知道g(n)=6n或是O(6n)的潜在大哦符号f(n)

现在,我们可以简化一下6大哦O(n)吗?是! 在这种情况下g(n) = n,因此:

c*g(n)      >=  f(n)    
c*n         >=  6n + 4    

让我们选择,c = 7因为左边的增加比右边的增加快。

7*n         >=  6n + 4

我们看到以上对于所有n大于或等于都是正确的n0 = 4。因此,O(n)是的潜在大哦符号f(n)。我们可以简化g(n)吗?不!

最后,我们发现最简单的Big Oh表示法f(n)O(n) 我们为什么要经历所有这些?因为现在我们知道它f(n)是线性的,因为它的Big Oh符号是线性复杂的O(n)。令人高兴的是,现在我们可以将f(n)其他算法的时间复杂度进行比较! 例如,我们现在知道,f(n)是相当的时间,复杂的功能h(n) = 123n + 72i(n) = nj(n) = .0002n + 1234等; 因为使用上面概述的相同简化过程,它们的线性时间复杂度均为O(n)

甜!!!


嗨,好的解释。我仍然没有什么疑问。1.由于变量值n,我们不能将6n + 4设为O(4)。这是答案吗?2.在简化时,您选择c = 7并相应地计算n0到4。是什么决定了c = 7且不小于7?因为基于c的值,n0会改变。
Pradeep 2012年

@Pradeep:对于1,您是正确的。进行更深入的解释:如果尝试O(4),这将使我们的不等式方程式产生c*4 >= 6n+4,对于c我们选择的任何一个方程式,我们总是可以找到一个值,其中所有n高于该值的值将使不等式成立。
Briguy37

@Pradeep:对于2,实际值cn0并不重要。n0对于c我们来说,重要的是存在。为了使这一点成立,对于的较大值,不等式的左侧必须比右侧增加更快nc=6这是没有用的(6n >= 6n+4永远不会是真的),所以我选择了c=7。我本来可以很容易地选择c=10,,c=734或者c=6.0000001仍然能够看到存在一些n0使不等式成立的事实n >= n0,这意味着我们正在测试的Big Oh是有效的。
Briguy37 2012年

感谢您的明确解释。这正是我一直在寻找的东西。再次感谢。
Pradeep 2012年

@ Pradeep:很高兴我可以帮助您:)
Briguy37

1

如果您的性能函数为6n + 4,则相关问题为“ 6什么?”。正如一则评论所问:您的常数代表什么?用物理学术语来说,您的常数因子的单位是什么?

O()表示法如此广泛地用于描述算法性能的原因是,没有可移植的方式来回答该问题。不同的处理器将花费不同数量的时钟周期和不同时间来执行相同的基本计算,或者它们可能以不同的方式组合相关的基本计算。不同的计算机语言或不同的正式和非正式描述(例如伪代码)将以难以直接比较的方式表示算法。即使使用相同语言的实现也可以以不同的方式表示相同的算法-琐碎的格式设置细节(如行数除外),您通常会有各种各样的任意结构选择来实现任何给定算法。

换一种方式来看:我们使用“算法”不是描述特定的实现,而是描述同一通用过程的整个潜在实现类。这种抽象忽略了实现的细节,而是倾向于记录一些具有一般价值的东西,而恒定的性能因素就是这些细节之一。

就是说,算法描述通常伴随着民俗,注释,甚至描述了在实际硬件上实际实现的性能的实际基准。这给了您一个大致的期望常数因素,但是也应该考虑一下,因为实际性能取决于诸如优化给定实现所需的工作量之类的事情。从长远来看,随着最新,最强大的处理器架构的变化,可比算法的相对性能往往会发生变化...

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.