我更喜欢少正式的定义并尽可能简单的数学。

有帮助吗?

解决方案

快速的注意,这几乎可以肯定是混乱的 大O符号 (这是一个上限)与西塔符号"Θ"(这是一个两边界).以我的经验,这实际上是典型的讨论在非学术的设置。道歉的任何混乱造成的。


大O复杂性可以与这个图表:

Big O Analysis

最简单的定义,我可以给大O符号是这样的:

大O符号是一个相对的表示的复杂的算法。

有一些重要的和故意选择的词,句子:

  • 相对的: 你只可以比较的苹果苹果。你不能比较的一个算法运算的乘法运算法,这种清单的整数。但是比较两种算法做算术运算(单乘法运算中,一个外)将告诉你一些有意义的事情;
  • 表示: 大O(在其最简单的形式)减少之间比较的算法,以一个单一的变量。该变量的选择是基于观测或假定。例如,排序的算法通常是比较,根据比较操作(比较两个节点,以确定其相对排序).这假定,比较昂贵。但是,如果比较便宜,但交换是很贵吗?它改变了比较;和
  • 复杂性: 如果需要我一秒种的10000元多久它会带我到排序的一个百万?复杂性的实例,这种实例是一个相对措施的东西。

回和重读上的时候你已经读到的其余部分。

最好的例子大-O我能想到的是这样做的算术运算。采取两个数字(123456和789012).基本的算术运算我们在学校是:

  • 外;
  • 减;
  • 乘法;和
  • 司。

每个这是一个操作或一个问题。一个方法解决这些被称为 算法.

除了是最简单的。你的线人数最多(的权利),并增加该数字在一个柱编写的最后一个数字,此外在的结果。该'十'的一部分,这一数字为结转到下一个柱。

让我们假设,这些数字是最昂贵的作业,在这种算法。按理说,添加这两种数字加在一起,我们必须加在一起有6位数字(可能随身携带一个第7次)。如果我们增加两个100位数字的号码我们一起做100个补充。如果我们加入 两个 10000名字号码我们要做10 000名增加。

看到的图案?的 复杂性 (被操作的数量)是直接成比例的数量的数字 n 在较大的数量。我们叫这个 O(n)线形的复杂度.

减相似(除了可能需要借款,而不是进行).

乘法是不同的。你的线人数最多,采取的第一个数字在底部的数字和乘以它在把对每个数字在上面的数字和所以,在通过每个数字。因此,要乘我们两6位数字的号码我们必须做36次乘法。我们可能需要做多达10个或11栏增加了获得最终结果。

如果我们有两个100位数字的号码我们需要做的10 000名乘法和200增加。两百万个数字号码我们需要做一个万亿美元(1012)乘法和两百万增加。

作为算法的尺度与正, 这是 O(n2)二次复杂性.这是一个很好的时间来介绍的另一个重要概念:

我们唯一关心的最重要部分的复杂性。

精明的可能有意识到,我们能快速操作的数量为:n2 +2n。但是正如你看到从我们的实例与两个数字的一个百万美元,第二期(2n)变得微不足道(占0.0002%的总业务的这一阶段)。

一个可以注意到,我们已经假设在最坏的情况下在这里。同时乘以6位数的数字,如果他们中的一个是4位数和6位数,然后我们只有24次乘法。我们仍然计算最糟糕的情况为'n',i。e时两者都是6位数字。因此,大O符号是关于最糟糕的情况的一个算法

电话簿

下一个最好的例子我能想到的是电话本,通常称为白页或类似的,但它将改变从一个国家向另一个国家。但我说的是那个名单的人的姓然后首字母或第一个名字,可能的地址然后电话号码。

现在如果你是指计算机查找手机号为"约翰*史密斯"在电话簿,其中包含1,000,000个名,你会怎么做?忽视的事实是,你可以猜测有多远在S的启动(假设你可以不了),你会做什么?

一个典型的实现可能会开放到中,采取500,000th 和比较"Smith"。如果发生这种情况是"史密斯,约翰",我们刚刚得到真正的幸运。更可能的是,"约翰*史密斯",将之前或之后的名称。如果这之后我们再除去一半的电话簿中的一半和重复。如果它是在那之前我们把第一半的电话簿中的一半和重复。等等。

这就是所谓的 二进制的搜索 而是每天使用编程中,你是否意识到这一点。

所以如果你想要找到一个名称在一个电话簿万名称实际上你可以找到任何名义通过这样做,至多20倍。在比较搜索算法,我们决定这种比较是我们的'n'。

  • 对于一个电话簿的3名需要2的比较(at most).
  • 7需要至多3。
  • 15需要4.
  • 对于1,000,000它需要20个。

这是令人吃惊的好不是吗?

在大O方面,这是 O(日志n)对数的复杂性.现在,对数问题可能是ln(基e)、日志10, 日志2 或者一些其他的基地。不管它仍然是O(日志n)就像O(2n2)和O(100n2)仍然是这两个O(n2).

它是值得的,在这一点来解释,大O可以用于确定三种情况与一个算法:

  • 最好的情况下: 在电话簿搜索,最好的情况是,我们找到的名字在一个比较。这个是 O(1)不断的复杂性;
  • 预期的情况: 如上面所讨论,这是O(日志n);和
  • 最坏的情况: 这也是O(日志n)。

通常我们不关心的最好的情况下。我们感兴趣的期望和最糟糕的情况。有时一个或其他的这些将更加重要。

回到电话簿。

什么如果你有一个电话号码,并希望找到一个名字?警方有一个反向电话簿,但这种查找拒绝向一般公众。或者是他们?从技术上讲你可以扭转查一些在一个普通的电话簿。怎么样?

你开始在第一名和比较数字。如果它是一个匹配,伟大的,如果不是,你移动到下一步。你必须这样做,因为电话簿 无序 (通过电话的数量无论如何)。

所以要找到一个名称给出电话号码(反查):

  • 最好的情况下: O(1);
  • 预期的情况: O(n)(用于500,000);和
  • 最坏的情况: O(n)(用于为1,000,000).

旅行推销员

这是一个相当有名的问题,在计算机科学的和值得一提。在这问题你必须N城镇。每个城镇被链接到1或多个其他城镇的道路的一定的距离。旅行推销员的问题是要找到最短的旅行,访问的每一个城镇。

听起来很简单?再想想。

如果你有3个城镇A、B和C的道路之间的所有对然后你可以去:

  • 一→B→C
  • 一→C→B
  • B→C→
  • B→一→C
  • C→一→B
  • C→B→

好吧,事实上还有不到,因为这些是相等的(A→B→C和C→B→一个相当,例如,因为他们使用相同的道路,只是在reverse)。

在现实中有3种可能性。

  • 采取这4个城镇和你有(请参考)12的可能性。
  • 5这是60个。
  • 6变为360.

这是一个函数的一个数学的动作叫做 因子.基本上:

  • 5! = 5 × 4 × 3 × 2 × 1 = 120
  • 6! = 6 × 5 × 4 × 3 × 2 × 1 = 720
  • 7! = 7 × 6 × 5 × 4 × 3 × 2 × 1 = 5040
  • 25! = 25 × 24 × … × 2 × 1 = 15,511,210,043,330,985,984,000,000
  • 50! = 50 × 49 × … × 2 × 1 = 3.04140932 × 1064

那么大-O的旅行推销员的问题是 O(n!)因或复杂的组合.

到时候你得到200城镇没有足够的时间留在宇宙中要解决的问题与传统的电脑。

一些思考。

时间多项式

另一点我想要快速提的是,任何算法,有一个复杂的 O(n一个) 是说 多项式的复杂性 或是可以解决在 时间多项式.

O(n),O(n2)等。是所有的多项式的时间。一些问题无法解决的多项式的时间。某些东西是在世界上使用,因为这个原因。 公共钥匙加密 是一个典型的例子。它在计算上是很难找到两个主要因素的一个非常大的数字。如果不是这样,我们不能使用公共钥匙系统,我们的使用。

无论如何,这就是我(希望简单的英语)解释的大O(修订本).

其他提示

它显示了一种算法的尺度。

O(n2):被称为 二次复杂性

  • 1项目:1秒
  • 10项目:100秒
  • 100项目:10000秒

注意到,项目数量增加了10倍,但时间增加的一个因素102.基本上,n=10和所以O(n2)给我们的伸缩因素n2 这是102.

O(n):被称为 线形的复杂度

  • 1项目:1秒
  • 10项目:10秒钟
  • 100项目:100秒

这段时间的项目数量增加了10倍,所以没时间。n=10和所以O(n)'s缩系数为10。

O(1):被称为 不断的复杂性

  • 1项目:1秒
  • 10项目:1秒
  • 100项目:1秒

项目的数量仍然增加了10倍,但是缩放因子的O(1)总是1。

O(日志n):被称为 对数的复杂性

  • 1项目:1秒
  • 10项目:2秒
  • 100项目:3秒
  • 1000项目:4秒钟
  • 10000项目:5秒钟

该数量的计算只增加了一个记录输入的价值。因此,在这种情况下,假定每个计算需要1第二,日志的输入 n 所需的时间,因此 log n.

这就是它的要旨。他们减少的数学下来,所以它不可能完全n2 或不管他们说是,但是这将可以支配因素的比例。

大O符号(也称为"渐进的增长"记号)是 什么样的功能"看起来像"当你忽略不断的因素的东西附近的起源.我们用它来谈谈 如何规模的事情.


基础知识

对于"足够"大输入...

  • f(x) ∈ O(upperbound) 装置 f "增长没有更快的比" upperbound
  • f(x) ∈ Ɵ(justlikethis) 意思是 f "增长完全一样" justlikethis
  • f(x) ∈ Ω(lowerbound) 装置 f "增长没有比" lowerbound

大O符号不在乎恒定因素:功能 9x² 是说"成长完全一样" 10x².也不大-O 渐近 符号表示的关心 非渐进 东西("的东西在靠近原产"或"时,会发生什么情况问题的大小小"):功能 10x² 是说"成长完全一样" 10x² - x + 2.

为什么你想要忽视了较小的部分方程?因为他们成为完全相形见绌的大部分公式作为你考虑的较大和较大比例;他们的贡献变得相形见绌,无关紧要的。(见例部分。)

把另一种方式,它的所有有关的 你去向无穷大。 如果你鸿沟的实际需时间通过 O(...), 你会得到一个恒定的因素的限制大的投入。 直观地这个有意义:功能"的规模,如"另一个如果你可以乘一个得到其他。也就是说,当我们说...

actualAlgorithmTime(N) ∈ O(bound(N))
                                       e.g. "time to mergesort N elements 
                                             is O(N log(N))"

...这意味着 "大不够"问题的大小N (如果我们忽略的东西附近的来源),还存在一些不断(例如2.5,完全由)这样的:

actualAlgorithmTime(N)                 e.g. "mergesort_duration(N)       "
────────────────────── < constant            ───────────────────── < 2.5 
       bound(N)                                    N log(N)         

有很多选择的恒定;通常"最好"的选择,被称为"定因素"的算法...但是,我们常常忽略这样我们忽略非最大的方面(见恒因素部分,用于为什么他们通常不物质)。你也可以认为上述公式作为约束,他说:"在最坏的情况下,所需的时间将永远不会更糟比大致 N*log(N), 内因素的2.5(a恒定因素,我们不关心)".

在一般情况下, O(...) 是最有用的一个,因为我们经常关心的最坏情况下的行为。如果 f(x) 表示的一些"坏"像处理器或存储器的使用,然后"f(x) ∈ O(upperbound)"装置"upperbound 是最糟糕的情况的处理器/存储使用"。


应用程序

作为一个纯粹的数学建造,大O符号不限于谈论处理时间和存储器中。你可以用它来讨论asymptotics的任何扩展都是有意义的,如:

  • 数量可能握手之中 N 人们在一个缔约方(Ɵ(N²), ,具体地说 N(N-1)/2, 但重要的是,它"秤像" )
  • 概率预计的人数已经看到了一些病毒市场为时间函数
  • 怎么网站等待时间尺度与处理单元的数量在CPU或GPU或计算机机群
  • 如何的热输出鳞CPU死亡作为一种功能的计数晶体管、电压,等等。
  • 多少时间一个算法需要运行,作为一个功能输入的大小
  • 有多少空间的一个算法需要运行,作为一个功能输入的大小

对握手的例子上,每个人都在一个房间震动的其他人的手上。在这个例子中, #handshakes ∈ Ɵ(N²).为什么?

回来了一点:数握手正是n-选择-2或 N*(N-1)/2 (每个N的人握手中的N-1的其他人,但是这种双重计数,握手,所以除以2):

everyone handshakes everyone else. Image credit and license per wikipedia/wikimedia commons "complete graph" article. adjacency matrix

然而,对于很大数目的人,线性的术语 N 是相形见绌和有效的贡献0的比例(在图表:该部分的空箱的对角线上的总框得到较小的作为参与者的数量变得更大)。因此,该行为是缩放 order N², 或数握手"变得像N2".

#handshakes(N)
────────────── ≈ 1/2
     N²

这是因为,如果空箱子上的对角线图(N*(N-1)/2选)甚至不存在(N2 选渐).

(临时的题外话从"普通英文":)如果你想证明自己,可以执行一些简单的代数上的比例来分裂为多个条款(lim 意思是"考虑的限制",只是忽略它,如果你还没有看到它,它只是符号"和N是真的真的很大"):

    N²/2 - N/2         (N²)/2   N/2         1/2
lim ────────── = lim ( ────── - ─── ) = lim ─── = 1/2
N→∞     N²       N→∞     N²     N²      N→∞  1
                               ┕━━━┙
             this is 0 in the limit of N→∞:
             graph it, or plug in a really large number for N

tl博士:数握手看起来像'x2这么多大价值,如果我们写下的比率#握手/x2,事实上,我们不需要 到底 x2握手甚至不该出现在小数点为任意大。

例如x=1百万,比#握手/x2:0.499999...


建筑物的直觉

这让我们使的发言就像...

"足够大的inputsize=N,无论什么恒的因素是,如果我 输入的大小...

  • ...我双倍的时间O(N)("线性时间")的算法的需要。"

    N →(2N)=2(N)

  • ...我双方(四)的时间O(N2)("二次时间")的算法的需要。" (例如一个问题100作为大需要1002=10000x只要...可能是不可持续的)

    N2 →(2N)2=4(N2)

  • ...我双立方(八倍)的时间O(N3)("立方体时间")的算法的需要。" (例如一个问题100作为大需要1003=1000000x只要...非常不可持续的)

    cN3 →c(2N)3=8(cN3)

  • ...我添加一固定数额的时间O(日志(N))("对数时间")的算法的需要。" (便宜!)

    c日志(N) →c log(2N)=(c log(2))+(c日志(N))=(固定金额)+(c日志(N))

  • ...我不改变的时间O(1)("时间常数")的算法的需要。" (最便宜!)

    c*1c*1

  • ...我"(基本)加倍"的时间一个O(N日志(N))的算法的需要。" (相当常见)

    这是不到O(N1.000001),其中你可能会愿意到呼叫基本上线

  • ...我可笑的增加时间的一个O(2N)("的指数的时间")的算法的需要。" (你会double(或三,等等。) 时间刚刚通过增加问题通过一个单元)

    2N → 22N = (4N)............把另一个方式。.. 2N → 2N+1 = 2N21 = 2 2N

[对于数学方式倾斜的,你可以老鼠在破坏者轻微sidenotes]

(与信贷 https://stackoverflow.com/a/487292/711085 )

(技术上的不断的因素,也许可问题在一些更复杂的例子,但我说的东西上面(例如在日志(N))这样的,它不会)

这些是面包和黄油的订单的增长的程序并应用了计算机科学家们利用作为参考点。他们看到这些所有的时间。(这样的话,你可以在技术上觉得"倍增加输入,使一个O(√N)的算法1.414倍速度较慢,"这是最好把它当作"这比对数,但是比线性".)


恒定因素

通常我们不在乎什么样的具体定因素,因为它们不影响功能的增长。例如,两个算法可能既带 O(N) 时间完成,但一个可以两次为缓慢。我们通常不太在乎,除非因素是非常大的,因为优化是棘手的事务( 当是优化过早? );也有的仅仅是行为的一种算法有一个更好的大O常常会改善性能的数量级。

一些渐进高级的算法(例如一个非比较 O(N log(log(N))) 排序)可以有如此大的恒定因素(例如 100000*N log(log(N))),或者开销,这是相对较大的喜欢 O(N log(log(N))) 一个隐藏的 + 100*N, 他们很少利用价值,甚至在"大的数据"。


为什么O(N)有时你能做的最好,即为什么我们需要的数据结构

O(N) 算法在某种意义上的"最好"的算法,如果你需要读过你所有的数据。的 很法阅读 一堆数据 O(N) 操作。载入存储器通常是 O(N) (或者更快,如果你有硬件支持,或者根本没有时间如果你已经读取的数据)。但是如果你触摸或者甚至 看看 在每一块的数据(或者甚至每一个其他数据),你的算法将取 O(N) 时间来执行这种期待。根多长时间你算法的实际需要,它将至少 O(N) 因为它花费了那时候看着所有的数据。

也可以这样说的 很法》的编写.所有算法,它打印出来N事会采取N时间,因为输出至少是长期(例如印刷出的所有排列(方式重新排列)的一组N玩牌是因子: O(N!)).

这促使使用 数据结构:数据结构需要阅读的数据仅仅一次(通常 O(N) 时间),加上一些任意数量的预处理(例如 O(N)O(N log(N))O(N²))我们尽量保持小。此后,修改数据结构(插入/缺失/etc.) 和查询的数据非常少的时间,例如 O(1)O(log(N)).然后你继续要做大量的查询!在一般情况下,更多的工作,你愿意做的时间提前,在较少的工作,你必须做到以后。

例如,说你已经纬度坐标的数以百万计的公路段,并希望找到的所有街十字路口。

  • 幼稚的方法:如果你曾坐标的一个街交叉路口,并希望审查附近的街道,你就要去通过的数百万段中的每一时间,检查每一个邻接关系。
  • 如果你只需要做这一次,它将不会是一个问题要做的幼稚的方法 O(N) 工作只有一次,但如果你想要做很多次(在这种情况下, N 次,一次针对每个段),我们就必须做 O(N²) 的工作,或10000002=1000000000000行动。不好(一个现代计算机可执行的大约一亿美元的操作每秒)。
  • 如果我们用一个简单的结构称为散列表(即时速查询表,也称为哈希或字典),我们支付少量费用通过预处理的一切 O(N) 时间。此后,只需要不断的时间平均来看看一些东西通过其关键(在这种情况下,我们的关键是经纬度坐标,圆形成一个网格;我们搜索的邻gridspaces其中只有9,这是一个恒定)。
  • 我们的任务就从一个不可行 O(N²) 到可管理 O(N), 和我们所要做的就是支付微小的成本做出散列表。
  • 比喻:这个比喻,在这种特定情况下是一个拼图:我们创建了一个数据结构的攻击的一些财产的数据。如果我们的路段就像拼图,我们把它们组通过匹配颜色和图案。然后,我们利用这个来避免这样做额外工作以后(对比拼图一样的颜色对方,不到其他每个拼图片)。

道德的故事:数据结构可以让我们加快了行动。甚至更先进的数据结构可以让你结合起来,延迟,甚或忽略行动中令人难以置信的聪明办法。不同的问题会有不同的类比,但它们希望所有涉及组织数据的方式,利用一些结构,我们关心,或者我们,人为地强加于它为记账。我们所做的工作的时间提前(基本上是规划和组织),现在重复的任务更容易得多!


实际的例子:可视化的订单的增长,同时编码

渐近表示法是,在其核心,相当独立的方案编制。渐进的符号是一个数学的框架思考如何的事情规模,并可以用许多不同的领域。那所说的...这是你怎么 适用 渐近记号来编码。

基础:每当我们进行互动与每一个元件是在集合的规模(例如一阵,一个设定,所有关键的地图上,等等), 或者执行一个迭代的循环,这是一个multiplcative因数的大小A.为什么我说"倍增因素"?--因为循环和功能(通过几乎定义)有乘法运行时间:次数、时间所做的工作环(或职能:的次数你打电话的功能,时间完成的工作在功能)。(这一持有,如果我们不做任何幻想,像跳过循环或退出该循环的早期,或改变控制流程中的职能的基础上参数,这是非常普遍的。) 这里是一些例子可视化技术,配合伪代码。

(这里, xs代表恒的时间单位的工作,处理指示,解释程序的操作码,无论)

for(i=0; i<A; i++)        // A * ...
    some O(1) operation     // 1

--> A*1 --> O(A) time

visualization:

|<------ A ------->|
1 2 3 4 5 x x ... x

other languages, multiplying orders of growth:
  javascript, O(A) time and space
    someListOfSizeA.map((x,i) => [x,i])               
  python, O(rows*cols) time and space
    [[r*c for c in range(cols)] for r in range(rows)]

实例2:

for every x in listOfSizeA:   // A * (...
    some O(1) operation         // 1
    some O(B) operation         // B
    for every y in listOfSizeC: // C * (...
        some O(1) operation       // 1))

--> O(A*(1 + B + C))
    O(A*(B+C))        (1 is dwarfed)

visualization:

|<------ A ------->|
1 x x x x x x ... x

2 x x x x x x ... x ^
3 x x x x x x ... x |
4 x x x x x x ... x |
5 x x x x x x ... x B  <-- A*B
x x x x x x x ... x |
................... |
x x x x x x x ... x v

x x x x x x x ... x ^
x x x x x x x ... x |
x x x x x x x ... x |
x x x x x x x ... x C  <-- A*C
x x x x x x x ... x |
................... |
x x x x x x x ... x v

实例3:

function nSquaredFunction(n) {
    total = 0
    for i in 1..n:        // N *
        for j in 1..n:      // N *
            total += i*k      // 1
    return total
}
// O(n^2)

function nCubedFunction(a) {
    for i in 1..n:                // A *
        print(nSquaredFunction(a))  // A^2
}
// O(a^3)

如果我们做的事稍微复杂,您可能仍然无法想象在视觉上有什么打算:

for x in range(A):
    for y in range(1..x):
        simpleOperation(x*y)

x x x x x x x x x x |
x x x x x x x x x   |
x x x x x x x x     |
x x x x x x x       |
x x x x x x         |
x x x x x           |
x x x x             |
x x x               |
x x                 |
x___________________|

这里,小可识别的概要,你可以画是什么事项;一个三角形是两维的形状(0.5A^2),就像一个正方形是两维的形状(A^2);恒因素的两个在这里仍然是在的渐进比率两者之间,但是我们忽略这样的所有因素...(存在一些不幸的细微差别,这项技术我不要走到这里;它可能会误导你。)

当然,这并不意味着循环和职能是坏;相反,他们是现代化编程语言,并且我们爱他们。然而,我们可以看到,我们编织的循环和职能和条件在一起,与我们的数据(控制流,等等。) 模仿的时间和空间,使用我们的节目!如果时间和空间的使用成为一个问题,那就是,当我们度假的聪明才智,找到一个简单的算法或数据结构,我们不认为,降低了增长。尽管如此,这些可视化技术(虽然他们并不总是工作)可以给你一个天真的想在最坏的情况下运行的时间。

这里是另一件事情我们可以认识到在视觉上:

<----------------------------- N ----------------------------->
x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
x x x x x x x x x x x x x x x x
x x x x x x x x
x x x x
x x
x

我们可以就重新安排这个,看看它是O(N):

<----------------------------- N ----------------------------->
x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
x x x x x x x x x x x x x x x x|x x x x x x x x|x x x x|x x|x

或者,也许你log(N)通过的数据,用于O(N*日志(N))的总时间:

   <----------------------------- N ----------------------------->
 ^  x x x x x x x x x x x x x x x x|x x x x x x x x x x x x x x x x
 |  x x x x x x x x|x x x x x x x x|x x x x x x x x|x x x x x x x x
lgN x x x x|x x x x|x x x x|x x x x|x x x x|x x x x|x x x x|x x x x
 |  x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x
 v  x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x

换个不相关的话题,但值得一提:如果我们执行哈希(例如一个词典/hashtable查阅),这是一个因素O(1)。那是相当快。

[myDictionary.has(x) for x in listOfSizeA]
 \----- O(1) ------/    

--> A*1 --> O(A)

如果我们做一些非常复杂的,例如用递归功能或分治的算法, 你可以使用 主理 (通常的),或在荒谬的情况下Akra-家穆罕默定理(几乎总是工作) 你看起来运行时间你算法在维基百科上。

但是,编程人员不认为这样是因为最终,算法,直只是成为第二本性。你会开始代码事效率低下,立即想到"我在做的东西 严重效率低下?".如果答案是"是的"和你预见到它实际上事,然后你能退后一步,并认为各种技巧,以使事情更快地运行(在回答几乎总是"使用hashtable",很少"使用一棵树",以及很少一些更复杂的).


摊销和平均情况的复杂性

还有概念"分摊"和/或"一般情况"(注意,这些都是不同的)。

平均情况:这不过是使用大O符号的预期价值的一个函数,而不是功能本身。在通常情况下你考虑所有输入的可能性相同,平均情况下,只是平均的运行时间。例如快速排序,即使在最糟糕的情况是 O(N^2) 对于一些非常糟糕的投入,平均情况下是通常的 O(N log(N)) (真的很糟糕的投入是非常小的数目,使少数,我们没有注意到他们的平均情况)。

摊销最糟糕的情况:一些数据结构可能有一个最坏情况的复杂性,这是大的,但能保证如果你做了许多的这些行动中,平均工作量将比最坏的情况。例如,你可以有一个数据结构,通常需要不断 O(1) 时间。然而,偶尔也会打嗝',并采取 O(N) 时间为一个随机的操作,因为也许它需要做的一些记账或收集垃圾什么的...但它承诺你,如果它不打嗝,它不会打嗝再次N更多的行动。最糟糕的情况下,成本仍然是 O(N) 每操作,但摊销成本的 过多的运行O(N)/N = O(1) 每操作。因为大的行动充分罕见,大量的临时工作可以被认为是融合在其他的工作作为一个恒的因素。我们说这工作就是"分摊"超过一个数量足够大的话,它就会消失渐进.

这个比喻对于分摊的分析:

你驾驶一辆汽车。偶尔,你需要花上10分钟会到 气站,然后花上1分钟加气罐气体。如果你这样做的每一次你去任何地方与你的车(花10 几分钟开车去加油站花了几秒钟,填补了一个 几分之一加仑),这将是非常低效率的。但如果你填 坦克一次每隔几天,11分钟花开车去 气站是"分摊"超过一个数量足够大的旅行, 你可以忽略它假装你所有的旅行都是也许5%的更长的时间。

比较之间的平均情况和分摊的最糟糕的情况下:

  • 平均情况:我们做一些假设对我们的投入;即如果我们输入具有不同的概率,那么我们的产出/运行时,会有不同的概率(这是我们需要的平均数).通常我们假设,我们的投入都是同样有可能的(统一的概率),但是如果现实世界的输入不适合我们的假设的"平均输入",平均输出/运行的计算可能是毫无意义的。如果你预见均输入随机虽然这是有用的,想想!
  • 分期摊销,最坏的情况:如果你使用分摊的最坏情况的数据结构、性能保证是内摊销最糟糕的情况下...最终的(即使投入的选择由一个邪恶的魔鬼谁知道一切,是试图去你的)。通常我们会用它来分析算法可能非常'时断时续'的表现意想不到的大问题,但随着时间的推移,执行以及其他算法。(然而,除非你的数据结构上的限制对于很多出色的工作,它愿意延迟,一个邪恶的攻击者也许可以强迫你能赶上最大量的拖延工作,所有在一次。

不过,如果你 合理的担心 有关攻击者,还有许多其他算法的攻击担心除了分期偿付的平均情况。)

两个平均情况和分摊是非常有用的工具,用于思考和设计与扩展中心。

(见 差之间的平均情况和分摊的分析 如果有兴趣对这一题.)


多层面的大-O

大多数时候,人们没有意识到,有一个以上变量的工作。例如,在一串的搜索算法,你的算法可能需要一段时间 O([length of text] + [length of query]), 即这是线性在两个变量 O(N+M).其他更天真的算法可以 O([length of text]*[length of query])O(N*M).忽视了多个变量是最常见的一个疏忽,我看到在算法的分析,并且可以盘口你当设计一种算法。


整个故事

请记住,大O不是整个故事。你可以大大加速了一些算法通过使用缓存,使得他们cache-忘记,避免瓶颈,通过与RAM而不是盘,使用并行处理,或者做工作的时间提前--这些技术往往是 独立的 为进的增长"大-O"符号表示的,虽然你会经常看到的核心数量在大O符号的平行的算法。

还铭记的是,由于隐藏的约束程序,则可能不真正关心的渐进的行为。你可以工作为界数量的数值,例如:

  • 如果你在排序的东西,像5的元素,你不想使用的迅速 O(N log(N)) 快速排序;你想要使用插入排序,这种情况发生执行以及对小的投入。这些情况经常出现在分治的算法,在那里你分手的问题纳入较小和较小的子问题,例如递归的排序,快速傅里叶变换或矩阵的乘法运算。
  • 如果某些价值观都是有效地为界,由于某些隐藏的事实(例如平均人的名字是轻轻界在也许是40信,人的年龄是轻轻地界定在大约150).你还可以施加限在你输入有效地使条款不变。

在实践中,甚至其中的算法,它具有相同或类似的渐近性能、它们的相对优点,实际上可能被驱动通过其它的事情,例如:其他业绩因素(快速排序而成了归并排序都是 O(N log(N)), 但快速排序的优点CPU缓存);非性能的考虑因素,如易于执行;是否库是可用的,以及如何有信誉和保持图书馆。

程序还将运行速度较慢的上一500MHz计算机vs2GHz计算机。我们真的不考虑此作为资源的一部分边界,因为我们认为的扩展条款的机资源(例如每个时钟周期),不是每个真正的第二。然而,也有类似的事情,它可'秘密'影响的性能,例如你是否下运行的模拟或编译器是否优化的代码或没有。这些可能会使一些基本的业务需要更长的时间(即使是相对于对其他),或甚至加速或放慢一些行动渐(甚至相对于每一个其他)。效果可能是小型或大型之间的不同执行和/或环境。你开关语言或机勉强维持这些额外的工作?这取决于一百个其他原因(必要性、技能、同事、程序员的工作效率的货币价值的时间,熟悉程度,解决办法,为什么不会或GPU,等等),这可能是更重要的性能。

上述问题,如编程语言,几乎从未被视为一部分的不断因子(他们也不应该被当);然而,人们应该意识到他们,因为 有的时候 (虽然很少),他们可能会影响的事情。例如在cpython,当地的优先权排队的实现是渐进的非最佳(O(log(N)) 而不是 O(1) 为你的选择插或找到-分钟);你用另一个的执行?可能不是,由于C的实现是可能速度更快,并有可能是其他类似问题的其他地方。有的权衡;有时他们的问题和有时他们没有。


(编辑:"普通英文"的解释,在这里结束。)

数学的增编

为了完整性、精确定义的大O符号如下: f(x) ∈ O(g(x)) 意味着"f渐上界const*g":忽略下面的一切一些有限值x,存在一个常这样, |f(x)| ≤ const * |g(x)|.(其他符号如下:就像 O 意味着≤, Ω 意味着≥.有小写的变体: o 装置 <, ω 意味着>.) f(x) ∈ Ɵ(g(x)) 意味着这两个 f(x) ∈ O(g(x))f(x) ∈ Ω(g(x)) (高和较低的界g):存在着一些常这样,f将永远躺在的"乐队"之间 const1*g(x)const2*g(x).它是最强的渐近的声明您可以使和大约相当于 ==.(对不起,我当选为延迟提的绝对值符号,直到现在,为清楚起见;特别是因为我从来没有见过负值出现在一个计算机科学的上下文。)

人经常会使用 = O(...), ,这或许是比较正确的'comp-sci符号,完全是合法的使用;"f=O(...)"读"f了.../f xxx界...",被认为是"f是一些表达其asymptotics是...".我被教导使用更严格的 ∈ O(...). 意思是"是一个要素"(仍读作之前)。 O(N²) 实际上是一个 等价类, ,也就是说,它是一套的东西,我们认为是相同的。在这种特定情况下, O(N²) 包含的元素,如{2 N², 3 N², 1/2 N², 2 N² + log(N), - N² + N^1.9,...}并且是无限大,但它仍然是一个集。的 = 符号可能更常见的一,并且甚至使用的文件,由世界着名的计算机科学家。此外,它通常的情况是,在休闲的环境,人们会说 O(...) 当他们的意思 Ɵ(...);这在技术上是真实的,因为设定的事情 Ɵ(exactlyThis) 是一个子集 O(noGreaterThanThis)...和它更容易类型。;-)

编辑:快速的注意,这几乎可以肯定是混乱的 大O符号 (这是一个上限)与西塔notation(这既是一个上限和下限).在我的经验,这实际上是典型的讨论在非学术的设置。道歉的任何混乱造成的。

在一个句子:作为你的作业去了,多久才能完成吗?

显然那只是使用"尺寸"的输入及"时间"作为输出同样的想法适用于如果你想谈谈存储器的使用等。

这里有一个例子,在那里我们有N T恤衫我们要干的。我们 假设 这是令人难以置信的快得到他们在干燥的位置(即人类的相互作用可以忽略不计).这不是这种情况下,在现实生活中,当然...

  • 使用洗衣线外:假设你有一个无限大的后院,洗干O(1)的时间。但是你拥有它,它会得到相同的阳光和新鲜空气,这样的大小不影响的干燥的时间。

  • 使用烘干机:你把10衬衫在每一个载荷,然后他们做了一个小时以后。(忽略的实际数字在这里—他们是无关紧要的。) 所以干50需要衬衫 关于 5倍,只要干燥10衬衫。

  • 把一切都在播放橱柜:如果我们把一切都放在一大堆而只是让一般温暖做到这一点,它将需要很长时间中的衬衫,以获得干。我可不喜欢猜测的细节,但我怀疑这是至少O(N^2)—如你所增加的洗载、干燥的时间增加更快。

一个重要方面"大O"符号是它 不不 说的算法将以更快的速度对于给定的大小。采取一hashtable(串钥匙,整数值)与一系列对(string,integer)。是它快找到一个关键在hashtable或元件阵列,根据一串?(即为阵,"找到的第一个元素弦的部分是否匹配给定的关键。") Hashtables一般摊余(~="平均")O(1)—一旦他们成立,它应该采取大约同一时间要找到一项在100项目表作为一个1,000,000个条目表。找到一个元件阵列(根据内容而不是指数)是线性的,即O(N)—平均来说,你们要看一半的项目。

这不会使hashtable快于一系列用于查找的?不一定。如果你已经有了一个非常小的集合,条目,一系列可能以更快的速度—你可以检查所有串的时间,它需要只要计算的哈希码一个你看。作为该数据集增长较大,但是,hashtable最终将击败阵列。

大O描述了一个上限增长的行为的一种功能,例如运行的程序,当投入,成为很大。

实例:

  • O(n):如果我的双尺寸输入运行时双打

  • O(n2):如果输入的大小的两倍运行时的四倍

  • O(日志n):如果输入的大小的两倍运行时增加一个

  • O(2n):如果输入的尺寸增大的一个,运行时双打

输入的大小通常是在空间中位的需要表示输入。

大O符号是最常用的程序作为一个近似测量的时间长度计算的(算法)将采取完成函数表示的尺寸的输入设置。

大O是有用的比较以及两个算法,将扩大为输入的数量增加。

更确切地说 大O符号 是用来表达的渐进的行为的功能。这意味着如何功能的行为与它的方法无穷大。

在许多情况下的"O"的一个算法将分成以下一种情况:

  • O(1) -时间到完整是相同的,无论大小的输入设置。一个例子是在访问一个阵元的索引。
  • O(日志N) -时间来完成增加的大致符合log2(n)。例如1024项目需要大约两倍长,为32个项目,因为Log2(1024)=10和Log2(32个)=5.一个例子是找到一个项目中的一个 二进制的搜索树 (BST).
  • O(N) -时间来完成这一尺度的直线尺寸的输入设置。换句话说,如果你双倍的项目数在输入设置的,算法需要大约两倍长。一个例子是计算数量中的项链表。
  • O(N记录N) -时间来完成增加的项目数次的结果Log2(N)。这样的一个例子是 堆的排序快速排序.
  • O(N^2) -时间来完成大约等于广场的数量的项目。这样的一个例子是 泡沫进行排序.
  • O(N!) -时间,以完成是因为输入的设定。这样的一个例子是的 旅行推销员问题的强力方案.

大O忽略的因素,不利于在一个有意义的方式成长曲线函数为输入大增加了向无穷大。这意味着常是加入或乘以该职能简单地被忽略。

大O只是一个方式"表达"自己在一个共同的方式,"多少时间/空间才能运行我的代码?".

你可以经常看到O(n),O(n2),O(nlogn)等等,所有这些都只是方式显示;怎么算法改变吗?

O(n)意大O n,现在你可能会想,"是什么n!?" 好的"n"是量的因素。像你想寻找一个项目的一个阵列。你会看上的每一个元件,如"你是正确的元素/项目?"在最坏的情况下,该项目是在最后一指数,这意味着,它采取尽可能多的时间,因为有项目列表,因此可通用的,我们说"噢嘿,n为公平的定量的价值。".

那么你可能了解什么是"n2"装置,但更具体、玩的认为你有一个简单的、最简单的排序的算法;bubblesort.这个算法的需要来看,通过整个列表,对每一个项目。

我的名单

  1. 1
  2. 6
  3. 3

流动,这里将是:

  • 比较1和6,这是最大的?"确定"6是在正确的位置、前进!
  • 比较6和3,哦,3小!我们走,Ok的表改变了,我们需要开始从一开始就现在!

这是O n2 因为,你需要看看所有的列表中的项目有"n"的项目。对于每一个项目,你看看所有项目的一旦更多,用于比较,这也是"n",因此,对于每一个项目,你看起来"n"时的含义n*n=n2

我希望这是为简单的,你想要它。

但是记得,大O只是一种方式来experss自己的方式的时间和空间。

<强>大O描述了一种算法的基本缩放性质。

有很多的信息大O不会告诉你一个给定的算法。它减少到骨并提供有关的算法的缩放性质唯一信息,具体地,资源使用如何(认为时间或存储器)的算法规模的响应于“输入大小”。

考虑一个蒸汽发动机和火箭之间的差异。他们不只是不同品种的同样的事情(如,说,普锐斯引擎与兰博基尼引擎),但他们显着不同种类的推进系统,其核心。蒸汽机可能比玩具火箭快,但没有蒸汽活塞发动机将能够实现轨道运载火箭的速度。这是因为这些系统有关于所需的燃料的关系不同的缩放特性(“资源使用”),以达到给定的速度(“输入大小”)。

这是为什么如此重要?因为有可能在大小上有所不同因素高达一万亿的问题软件交易。考虑了一会儿。必要前往月球和人步行速度的速度之间的比小于10,000:1,并且与在输入尺寸软件可面对的范围是绝对小。而且由于软件可能面临输入大小有一种算法的大O复杂性的潜在天文范围,这是基本的缩放性质,胜过任何实现细节。

考虑规范排序的例子。冒泡排序是O(n 2 ),而合并排序是O(n log n)的。比方说,你有两个分类应用,它采用冒泡排序和应用B的使用合并排序,并让我们说,周边的30个元素的应用程序A的输入大小为排序比应用程序B快1000倍,应用程序A。如果你从来没有排序远远超过30个元素则很明显,你应该更喜欢应用程序A,因为它是在这些输入的大小要快得多。但是,如果你发现,你可能有一级千万的项目进行排序,然后你会想到的是,应用程序B实际上最终被上千次的应用程序更快的在这种情况下,完全是由于每路算法尺度。

下面是普通英语动物寓言我倾向于解释大O的普通品种时使用

在所有的情况下,宁可算法越往上列表上的那些列表上较低。然而,在移动到一个更昂贵的复杂类的成本显著变化。

<强> O(1):

没有增长。不管有多大的问题是,你可以在相同的时间内解决这个问题。这是有点类似于广播它需要能量相同量的广播在给定的距离,而不管位于所述广播范围内的人的数目。

<强>为O(log Ñ):

此复杂性是相同的 O(1)不同之处在于它只是有点差。对于所有的实际目的,你可以认为这是一个非常大的恒定比例。在处理千分1个十亿项之间工作的差异仅仅是一个因子6。

<强> O(名词的):

解决问题的成本正比于问题的大小。如果您的问题在双打大小,那么解决方案的成本增加一倍。由于大多数的问题必须被扫描到以某种方式的计算机上,作为数据输入,磁盘读取,或网络流量,这通常是一种经济实惠的缩放因子。

<强> O(名词的日志名词的):

此复杂性是非常类似的 O(名词即可。对于所有的实际目的,两者是等价的。这种复杂程度一般会仍然被认为是可扩展的。通过调整假设一些的 O(名词的日志名词算法可以转化成的 O(名词的) 算法。例如,边界键的大小减少了从<强> 0分选(名词的日志名词 O(名词

<强> O(名词 2 ):

成长,如正方形,其中名词的是一个正方形的边的长度。这是相同的增长速度的“网络效应”,每个人都在网络中可以知道每个人在网络中的其他人。成长是昂贵的。大多数的可扩展解决方案不能与这种复杂性没有做显著体操用的算法。这一般适用于所有其他多项式复杂 - 的 O(名词 ķ - 以及

<强> O(2 名词 ):

不结垢。你有没有解决任何非平凡大小问题的希望。可用于知道什么以避免,并为专家们找到近似算法,它是在的 O(名词 ķ

大O是的算法多少时间/空间利用相对于它的输入的大小的量度。

如果一个算法是O(n),则时间/空间将以相同的速率作为其输入增加。

如果一个算法是O(n 2 ),则时间/空间在其输入端的速率增加的平方。

等。

这是非常难以测量速度的软件程序,并且当我们尝试,答案可能是非常复杂和充满了例外和特殊情况。这是一个大问题,因为所有这些例外和特殊情况下会分散注意力,无益时我们想比较两种不同程序与另一个找出来这是最快的.

作为结果的所有这种无益的复杂性,人们尝试描述的速度的软件程序的使用最小的和最复杂的(数学)的表达可能的。这些表情非常非常粗近似值:虽然,有一点运气,它们将捕获的"实质"是否是一个软件是快还是慢。

因为他们是近似值,我们使用的字母"O"(大哦)中的表达,作为《公约》的信号读者,我们正在做一个总的过于简单.(并且确保没有人错误地认为表达任何方式准确).

如果你读"哦"为意指"为"或"大约"你不会走的太远错误的。(我认为选择的大-哦,可能已经尝试的幽默感).

唯一的事情,这些"大哦"的表达方式试图做的是描述了如何从该软件缓慢下来,我们增加量的数据,该软件已经处理。如果我们双量的数据,需要加以处理,该软件需要两倍的时间来完成它的工作?十倍多久?在实践中,有一个非常有限数量的大-哦,表达,你将会收到和需要担心:

好:

  • O(1) :该方案需要同时运行,无论多么大的输入。
  • O(log n) 对数:程序的运行时增加缓慢,甚至与大增加尺寸的输入。

坏:

  • O(n) 线性:该程序运行时间比例增加到尺寸的输入。
  • O(n^k) 多项式:-处理时间的增长速度更快和更快的-为多项式功能-如尺寸的输入增加。

...和丑陋的:

  • O(k^n) 指数 程序的运行时增加非常迅速地与适度增加问题的大小-这是唯一切实处理小数据集使用指数的算法。
  • O(n!) 因子 该程序运行时间将更长的时间比你可以负担得起等待任何东西,但非常小的和最微不足道的-表面上的数据集。
  

什么是大澳的纯英文解释吗?用尽可能少正式定义尽可能和简单的数学。

<强>的需要对于大O符号的简明英语说明:

当我们计划,我们试图解决的问题。我们的代码被称为算法。大O表示法允许我们的我们的算法的最坏情况下的性能比较的标准方法。硬件规格随时间变化和在硬件的改进可以减少它采用的算法来运行的时间。但更换硬件并不意味着我们的算法是随着时间的推移任何好转或改善,因为我们的算法仍然是相同的。因此,为了使我们能够比较不同的算法,以确定是否一个好与否,我们用大O符号。

什么的大O符号是一个普通的英语解释:

不是所有的算法在相同的时间内运行,并且可基于在输入项目,我们称之为名词的数目。在此基础上,我们认为最坏的情况分析,或上限的运行时间的名词的越来越大。我们必须意识到什么的名词的是,因为许多大O符号的引用它。

一个简单直接的答案可以是:

大O代表该算法最坏的时间/空间。该算法将永远不要超过该限制更多的空间/时间。大O表示时间/空间在极端情况下的复杂度。

好的,我的分钱小费。

大-O,是的增加率资源的按程序消耗,w.r.t.问题实例尺寸

资源:可能是总的CPU时间,可能是最大的RAM空间。缺省情况下是指CPU时间。

说的问题是 “查找的总和”,

int Sum(int*arr,int size){
      int sum=0;
      while(size-->0) 
         sum+=arr[size]; 

      return sum;
}

问题实例= {5,10,15} ==>问题实例尺寸= 3,迭代在回路= 3

问题实例= {5,10,15,20,25} ==>问题实例尺寸= 5次迭代在回路= 5

有关尺寸的输入的“n”的节目是在阵列中的“n”次迭代的速度增长。因此大O是N表示为O(n)的

说的问题是 “查找结合”,

    void Combination(int*arr,int size)
    { int outer=size,inner=size;
      while(outer -->0) {
        inner=size;
        while(inner -->0)
          cout<<arr[outer]<<"-"<<arr[inner]<<endl;
      }
    }

问题实例= {5,10,15} ==>问题实例尺寸= 3,总迭代= 3 * 3 = 9

问题实例= {5,10,15,20,25} ==>问题实例尺寸= 5,总迭代= 5×5 = 25

有关尺寸的输入的“n”的节目是在在数组“N * N”次迭代的速度增长。因此大O是N 2 表示为为O(n 2

大O符号是描述在空间或运行时间条件的上界的算法的方法。的n是在该问题元件(,阵列的大小即,节点在树号码等)的数量,我们有兴趣在描述当n增加大的运行时间。

当我们说一些算法是O(F(N))我们的意思是运行时间(或所需的空间)由算法总是低于某个常数倍F(N)。

要说二进制搜索具有O(logn)时间的运行时间是说,存在一些常数c,你可以通过该相乘的log(n)总是比二进制搜索的运行时间大。在这种情况下,你总是具有的log(n)的比较的一些常数因子。

在换句话说其中g(n)是你的算法的运行时间,我们说,G(N)= O(F(N))时G(N)<= C * F(N)当n> k,其中c和k为一些常数。

"什么是一个普通的英语解释的大O?与作为正式点 定义为可能的和简单的数学。"

这样一个美丽的简单和简短的问题似乎至少应该同样简短的回答,就像一个学生可能会收到过辅导。

大O符号的简单地告诉你太多的时间*算法可以运行之内, 在条款 只量输入数据**.

(*在一个美好的, 单元免 感觉时间!)
(**这是什么问题,因为人们会 总是 想要更多, 是否他们生活在今天或明天)

好了,有什么美妙的关于大O符号,如果这是它做什么?

  • 实际上,大O分析 所以有益和重要的 因为大O把重点完全算法的 自己的 复杂性和完全 忽略了 任何东西仅仅是一个相称性恒定状JavaScript引擎的速度CPU,你的互联网连接,以及所有那些事情变得迅速成为可笑的过时作为模型 T.大O侧重于业绩只能在方法问题同样多的人生活在目前或未来。

  • 大O符号还闪耀的一个焦点直接放在最重要的原则,计算机编程工程,这一事实激励所有优秀的程序员,以保持思想和梦想的:只有这样,才能实现结果超出了缓慢前进的技术来 创造一个更好的算法.

算法例(Java):

// given a list of integers L, and an integer K
public boolean simple_search(List<Integer> L, Integer K)
{
    // for each integer i in list L
    for (Integer i : L)
    {
        // if i is equal to K
        if (i == K)
        {
            return true;
        }
    }

    return false;
}

算法的说明:

  • 这种搜索算法的一个列表中,项目通过项目,寻找一个关键,

  • 迭代,每个项目的清单,如果这是钥匙然后返回真的,

  • 如果循环已经完成了没有找到钥匙,return False.

大O符号表示该上限的复杂程度(时间、空间..)

找到大O时间上的复杂性:

  • 计算出有多少时间(关于尺寸的输入)最糟糕的情况下需要:

  • 最坏的情况:关键不在名单。

  • 时间(最糟糕的情况下)=4n+1

  • 时间:O(4n+1)=O(n)|在大,常被忽视

  • O(n)~直线

还有大-欧米茄,其代表的复杂性,最好的情况下:

  • 最好的情况:关键是第一个项目。

  • 时间(最好的情况下)=4

  • 时间:Ω(4)=O(1)~瞬间\恒

大O

f(x)=O((x)),当x去(例如,=+∞)意味着有一个功能 k 这样的:

  1. f(x)= k(x)(x)

  2. k界在一些附近的一个(如果=+∞,这意味着有数字N and M例如,对于每x>N|k(x)| < M)。

换句话说,在平原文: f(x)=O((x)),x→一,意味着在一个附近的一个, f 分解到的产品的 和一些有界函数。

小o

顺便说一下,这里是为了比较的定义小o.

f(x)=o((x)),当x去意味着有一个功能k这样的:

  1. f(x)= k(x)(x)

  2. k(x)转到0时x去。

  • 罪x=O(x)当x→0.

  • 罪x=O(1)当x→+∞,

  • x2 +x=O(x)当x→0,

  • x2 +x=O(x2)当x→+∞,

  • ln(x)=o(x)=O(x)当x→+∞.

注意! 记号与平等的标志"="使用"虚假平等":这是真的,o(g(x))=O(g(x)),但是虚假的,O(g(x))=o(g(x))。同样,这是确定的,要写"ln(x)=o(x)当x→+∞",但式"o(x)=l(x)"会做没有意义的。

更多的例子

  • O(1)=O(n)=O(n2)当n→+∞(但不是周围的其他方法,等于是"假"),

  • O(n)+O(n2)=O(n2)当n→+∞

  • O(O(n2))=O(n2)当n→+∞

  • O(n2)O(n3)=O(n5)当n→+∞


这里是维基百科文章: https://en.wikipedia.org/wiki/Big_O_notation

大O符号是描述如何快速的算法将运行给出的输入参数,我们称之为“N”任意数目的方法。因为不同的机器以不同的速度运行,并简单地说,算法需要5秒不告诉你很多,因为当你可能正在运行一个4.5 GHz的八核处理器的系统,我可以运行它在计算机科学有用一个15岁,800 MHz系统,这可能需要更长的时间,无论算法。因此,而不是指定的算法在时间上如何快速运行,我们说如何快速的输入参数号,或“n”来运行。通过描述这种方式的算法,我们能够算法的速度比较,而不必考虑到计算机本身的速度。

不知道我在进一步促进了主题,但仍然想我会分享:我一旦发现的这个博客帖子有一些非常有用(虽然很基本的)上的大O解释和例句:

通过实例,这有助于获得裸基础知识到我的龟甲状头骨,所以我认为这是一个漂亮的后裔10分钟的阅读,让你在正确的方向前进。

您想知道所有有知道大O字吗?我也是。

所以要大O字的谈话,我将使用在他们刚一拍的话。每字一个音。小词很快。你知道这些话,我也一样。我们将用文字与一个声音。他们很小。我相信你会知道一切的,我们将使用的话!

现在,让你和我谈工作。大多数时候,我不喜欢的工作。你喜欢的工作?这可能是因为你做的话,但我相信,我不知道。

我不喜欢去工作。我不喜欢在工作中花费时间。如果我有我的方式,我想刚玩,做有趣的事情。你像我一样有同样的感觉?

现在有时,我必须去上班。这是可悲的,但却是事实。所以,当我在工作,我有一个规则:我尽量少做工作。由于附近没有工作,我可以。然后我去发挥!

因此,这里的大新闻:大O可以帮我不能做的工作!我可以打更多的时间,如果我知道大O.更少的工作,更多的玩!这就是大O字帮我做的。

现在我有一些工作。我有这个名单:一,二,三,四,五,六。我必须添加所有的东西在列表中。

哇,我讨厌的工作。但哦,我必须这样做。所以在这里我走了。

一加二等于五...加3等于6 ...四是......我不知道。我迷路了。这太难了,我在我的头上做。我对这样的工作并不很在意。

所以我们不要做的工作。让你和我只是觉得这是多么不容易。我多少工作必须做的,添加六个数字?

好了,让我们来看看。我必须添加一个和两个,然后添加到三,然后添加到四......一切的一切,我算6补充道。我必须做6增加了解决此问题。

下面来大O,告诉我们这个数学是多么的艰难。

大O说:我们必须做6增加了解决此问题。一加,对于每一件事情从一到六。工作的六个小比特...工作的每个比特是一个附加

好了,我不会做现在的工作,将其添加。但我知道这将是多么艰难。这将是6增加。

哦,不,现在我有更多的工作。啧。谁做这样的东西?!

现在,他们问我加从一到十!我为什么要这么做?我不想增加一到六个。从一个新增十...好...这将是更硬!

如何更硬会是谁?我如何做更多的工作必须做的?我需要更多或更少的步骤是什么?

嗯,我想我会做十加...一个每一件事情从一到十。十是超过6条。我会的工作,更从一个添加到十比一到六!

我不想现在就加入。我只是想觉得它可能是如何努力增加那么多。而且,我希望尽快我可以玩了。

要添加一个至六个,即一些工作。但是你看,增加从一到十,那就是更多的工作?

大O是你的朋友和我的。大O有助于我们想起我们有多少工作要做,所以我们可以计划。而且,如果我们用大O字的朋友,他可以帮助我们选择工作不是那么难!

现在我们必须做新的工作。不好了。我不喜欢这个工作的事都没有。

在新的工作是:添加所有的东西从1到n

等待!什么是正?我错过了吗?我如何从一个添加到n,如果你不告诉我是什么ň?

好了,我不知道是什么ñ。我没有被告知。是你?没有?那好吧。因此,我们不能做的工作。呼。

不过,虽然我们不会做现在的工作,我们可以猜测它会很难,如果我们知道ñ。我们将不得不加N个的东西,对不对?当然!

现在,这里是大O,他会告诉我们,这项工作是多么不容易。他说:从一个到N,逐一加入所有的东西,为O(n)。要添加这些东西,[我知道我必须补充n次。] [1]这是很大的哦!他告诉我们,这是多么困难做一些类型的工作。

对于我来说,我觉得大O字就像一个大的,缓慢的,老板人。他认为人的工作,但他没有这样做。他可能会说,“T帽子的工作快。”或者,他可能会说,‘这工作是如此缓慢,辛苦了!’但他并没有做的工作。他只是着眼于工作,然后他告诉我们,它可能会花费多少时间。

我关心很多的大O.为什么?我不喜欢的工作!没有人喜欢工作。这就是为什么我们都爱大哦!他告诉我们,我们怎么快速的工作。他帮助我们思考的是如何努力工作。

嗯哦,更多的工作。现在,让我们没有做的工作。但是,让我们做一个计划去做,一步一步来。

他们给了我们十张一副扑克牌。他们都混合起来:七,四,二,六......不直的。而现在......我们的工作就是对它们进行排序。

Ergh。这听起来像一个大量的工作!

我们如何排序这个平台?我有个计划。

我将着眼于每对卡,通过对一对,通过甲板上,从第一个到最后。如果一对第一张牌是大,在对下一张牌是小,我换他们。否则,我去到下一对,等等等等......很快,甲板完成。

在甲板完成后,我问:为什么我更换卡在通?如果是这样,我必须做这一切再次,从顶部。

在某些时候,在一段时间内,不会有掉,而我们在甲板上的排序将被完成。这么多的工作!

那么,有多少工作会是这样,对卡这些规则进行排序?

我有十张。而且,大多数的时间 - 也就是说,如果我没有很多运气的 - 我必须通过甲板每次都要经过整个甲板多达十次,最多十个卡更换

大O,帮帮我吧!

大O进来说:对于N一副纸牌,对它进行排序这种方式将在O完成(N的平方)时间

他为什么别回答n的平方?

好了,你知道N.平方为n n次。现在,我明白了:N卡检查,达到什么可能直通甲板的n倍。这是两个回路,每n步。要做到这一点为n的平方很多工作。大量的工作,肯定的!

当像个大O表示,将采取为O(n的平方)工作

现在,他不次的平均值平方增加,在鼻子上。这可能是一些小的少一点,对一些情况。但是在最坏情况下,这将是近Ñ平方工作的步骤,以在甲板排序。

现在这里是大O大会是我们的朋友。

大O指出了:当n增加大,当我们梳理卡,工作变得比老刚刚附加这些-东西的工作更多更多努力。我们怎么知道呢?

好了,如果n得到真正的大,我们不关心什么,我们可能会添加到N或N的平方。

有关大N,N-平方是大于n大。

大O告诉我们,理清更硬,而不是添加一些东西。为O(n的平方)大于O(N)为大n多。这意味着:如果n得到真正的大牌,排序的n个东西混合甲板必须花费更多的时间,而不是仅仅加入正混事

大O没有解决不了的为我们工作。大O告诉我们的工作是多么不容易。

我有一副扑克牌。我没有对它们进行排序。你有帮助。感谢。

有没有卡排序更快速的方式?大O可以帮助我们吗?

是的,还有一个更快速的方式!这需要一些时间来学习,但它工作...它的工作原理相当快。你可以试试它,但你的时间每一步,不要失去你的地方。

在排序甲板这种新的生活方式,我们不检查双卡我们做了,而以前的方式。这是你的新规则进行排序此甲板:

一:我选择在我们的现在的工作甲板的一部分一张卡。您可以选择一个对我来说,如果你喜欢。 (第一次我们这样做,“我们现在上工作甲板的部分”是整个甲板,当然。)

二:我张开那张卡你选择在甲板上。这是什么张开;我怎么张开?嗯,我从一开始就卡下井,一个接一个,我找了一张比扩开卡更高。

三:我从末端卡最多去了,我找了一张比扩开卡更小。

在我发现这两张牌,我换他们,去寻找更多的卡交换。也就是说,我回到步骤二,并张开你选择了一些在卡上。

在某些时候,该循环(从2至3)将结束。当这个搜索的两部分在张开卡满足结束。然后,我们刚刚张开甲板与你在第一步中选择了该卡。现在,开始了几乎所有卡比扩开卡更小;而临近年底的卡比扩开卡更高。酷招!

四(这是最有趣的部分):我现在两个小甲板,比喷射卡一个更低,和一个更高。现在,我转到步骤之一,每个小甲板!也就是说,我从第一小甲板一步一开始,当工作完成后,我对来自下一小甲板一步一个开始。

我分手的部分甲板上,各部分,更小,更小的排序,在某些时候,我没有更多的工作要做。现在,这似乎慢,对所有的规则。但请相信我,这是不慢的。它比理清第一工作方式要少得多!

什么是称这一类?这就是所谓的快速排序!那种被一个叫 C.人造A. R.霍尔和他把它称为快速排序。现在,快速排序被使用所有的时间!

快速排序打破了在小的大甲板。也就是说,它在小的打破了很大的任务。

嗯。有可能是在那里一个规则,我想。为了使大任务小,打破他们。

此排序是相当快的。如何快速?大O告诉我们:这种需要为O(n log n)的工作要做,在平均情况。

它比第一个排序或多或少快?大O,请大家帮忙!

第一次排序是为O(n的平方)。但快速排序为O(n log n)的。你知道的n log n是小于n的平方,对于大N,对不对?嗯,这是我们怎么知道快速排序快!

如果你有排序甲板,什么是最好的方法是什么?那么,你可以做你想做的,但我会选择快速排序。

为什么我选择快速排序?我不喜欢的工作,当然!我想工作,只要我能完成它完成。

我怎么知道快速排序是较少的工作?我知道,为O(n log n)的小于为O(n的平方)。该O是更小,所以快速排序是较少的工作!

现在你知道我的朋友,大O.他帮助我们少做工作。如果你知道大O,你可以少做工作呢!

您学会了所有与我!你太聪明了!太谢谢你了!

现在这项工作完成后,让我们去发挥!


[1]:有一种方法来欺骗和从1到n,所有添加的所有事物在同一时间。命名为高斯一些孩子发现了这一点,当他8。我没有那么聪明了,所以不要问我他是如何做到

假设我们正在谈论的算法的 A ,它应该做的事,大小的数据集ñ

然后O( <some expression X involving n> )装置,在简单的英文:

  

如果您在执行A,此时不走运,可能需要X(n)的操作   完整。

碰巧,有某些功能(把它们看成实现的的 X(n)的)趋向于相当经常发生。这些是众所周知的,并且容易地进行比较(例如:1Log NNN^2N!等。)

通过谈论时比较这些的 A 并其他算法,很容易根据操作他们的数量可(最坏情况)要求的排名算法完成。

在一般情况下,我们的目标是找到或结构算法的 A 以这样的方式,这将有一个函数X(n)返回尽可能低的数目成为可能。

我更简单的方法来理解复杂的时间 他最常见的指标,用于计算时间复杂性大O符号。这将删除所有定因素,因此,运行时间估计可以在有关N的N的方法无穷大。在一般可以认为它是这样的:

statement;

是恒定不变的。运行时间表的声明将不改变关于N

for ( i = 0; i < N; i++ )
  statement;

是线性的。运行时间的循环是直接成比例N.当N倍,所以没有正在运行的时间。

for ( i = 0; i < N; i++ ) 
{
for ( j = 0; j < N; j++ )
  statement;
}

是二次的.运行时间为两个循环是成比例的平方。当N双人间,运行时间增加N*N。

while ( low <= high ) 
{
 mid = ( low + high ) / 2;
 if ( target < list[mid] )
 high = mid - 1;
 else if ( target > list[mid] )
  low = mid + 1;
else break;
}

是对数。运行时间算是成正比的次数N可以除以2。这是因为算法划分的工作领域中的一半,与每一次迭代。

void quicksort ( int list[], int left, int right )
{
  int pivot = partition ( list, left, right );
  quicksort ( list, left, pivot - 1 );
  quicksort ( list, pivot + 1, right );
}

是N*日志(N)。运行时间由N循环(迭代或递)是对数,因此算法是结合的线性和对数。

在一般情况下,做一些与每个项目的一个尺度是线性的,在做的事情与每一项目在两个方面是二次方程,并分工作地区中的一半是对数。还有其他大O措施,例如立法、指数、和平方根,但它们几乎没有共同点。大O符号被描述为O()哪里是衡量。的快速排序的算法将被描述为O(N*日志(N))。

注:没有这已考虑到最好,平均和最糟糕情况的措施。每个会有其自己的大O符号。还注意到,这是一个非常简单的解释。大O是最常见的,但它也更复杂,我已经显示。还有其他的符号,如大米茄,小o、和大西塔。你可能不会遇到他们之外的一个算法分析课程。

说你为了哈利·波特:完整的8电影合集[蓝光来自亚马逊和在同一时间网上下载同一部电影的集合。你要测试的方法更快。交付需要近一天到达,并下载大约30分钟前完成。大!所以这是一个紧张的比赛。

如果我为了几个蓝光电影像指环王的,暮光之城,黑暗骑士三部曲等,并在同一时间网上下载所有的电影吗?这一次,交付仍然需要一天就能完成,但网上下载需要3天才能完成。 对于网上购物,购买商品(输入)的数量不会影响交货时间。输出是恒定的。我们称此的 O(1)

有关的在线下载,下载时间是正比于电影文件大小(输入)。我们称此的 O(n)的

在实验中,我们知道,网上购物鳞比网上下载好。了解大O表示法,因为它可以帮助你分析的算法的可扩展性效率这是非常重要的。

注意:大O符号表示的算法的的最坏的情况即可。让我们假设的 O(1)和<强> O(n)的是上面的例子中的最坏的情况。

<强>参考 http://carlcheo.com/compsci

如果你在你的头上无穷大的概念适宜,然后有一个非常简短的介绍:

  

大O符号告诉你解决一个无限大的问题的成本。

和进一步

  

常因素是可以忽略的

如果您升级到能够以最快的速度跑两次你的算法一台电脑,大O符号不会注意到这一点。常数因子的改进是太小,即使在大O表示法的工作原理与规模被注意到。注意,这是大O符号的设计的有意一部分。

虽然任何“较大”大于常数因子可以被检测到,但是。

当兴趣做计算,其大小为“大”,足以被视为近似无穷大,那么大O表示法是大约解决您的问题的成本。


如果上面没有意义,那么你没有无限兼容的直观概念在你的头上,你应该不顾一切以上的;我知道,让这些想法严谨,或解释他们,如果他们是不是已经直观有效的唯一办法,就是先教你大O表示法或类似的东西。 (不过,一旦你很好的理解,将来大O符号,它可能是值得重新审视这些想法)

什么是一个普通的英语解释"大O"符号?

很快注意:

O在"大O"是指为"秩序"(或"订单")
因此你能获得其想法,从字面上,它是用来为什么要对它们进行比较。

  • "大O"做两件事:

    1. 估计多少步骤的方法计算机适用于完成一项任务。
    2. 促进这一进程比其他人,以便确定它是否是好还是不好?
    3. "大O'实现了上述两个标准化 Notations.
  • 有七个使用最多的符号

    1. O(1),用你的电脑被一个任务完成 1 步骤,它的优秀的、有序号1
    2. O(的),意指计算机完成任务 logN 步骤,其良好的,命令的第2号
    3. O(N)完成一个任务 N 步骤,其公平的,第3号命令
    4. O(NlogN),结束了任务 O(NlogN) 步骤,它不是好的,为了第4号
    5. O(N^2),得到一个任务完成 N^2 步骤,这是不好的,为了第5号
    6. O(2^N),得到一个任务完成 2^N 步骤,这是可怕的,为了第6号
    7. O(N!), 得到一个任务完成 N! 步骤,这是可怕的,为了第7号

enter image description here

假设你得到的符号 O(N^2), 不只你是清楚的方法N*N步骤,以完成一项任务,你也看到,这不好 O(NlogN) 从其排名。

请注意,在线结束,只是为了你更好的理解。有超过7符号,如果所有的可能性考虑。

在CS,设定步骤完成一项任务是所谓的算法。
在术语中,大O符号是用来描述的性能或复杂的算法。

此外,大O规定的最坏情况或衡量的上限的步骤。
你可以参考大-Ω(大Omega)为最好的情况下。

大-Ω(大Omega)notation(条)|汗学院

  • 摘要
    "大O"描述了算法的业绩和评估。

    或者地址正式的"大O"分类的算法和标准比较的过程。

以看它(在简单的英语)的最简单方法

我们正试图看到的输入参数的数量如何,影响算法的运行时间。如果您的应用程序的运行时间是成正比的输入参数的数量,那么它被认为是在正的大澳。

在上面的语句是一个好的开始,但是并不完全正确。

:一种更精确的解释(数学)

假设

N =输入参数数目

T(N)=表达该算法的运行时间作为n的函数

的实际功能

C =常数

F(N)=表达该算法的运行时间作为n的函数

的近似函数

然后尽可能大O而言,近似F(N)被认为是只要以下条件为真不够好。

lim     T(n) ≤ c×f(n)
n→∞

方程式读为 当n接近于无穷大,T N的,小于或等于c乘以F 2 N的

在大O符号此写为

T(n)∈O(n)

的n为n个的大O此被读为T

返回英语

根据数学定义如上,如果你说你的算法是n的大O,这意味着它是n的函数(输入参数数)或更快即可。如果你的算法是n的大O,那么它也会自动n的方阵的大澳。

的n大O意味着我的算法运行至少一样快这一点。你可以不看你的算法的大O符号,并说,它的缓慢。你只能说,它的速度快。

检查的出用于在大O的视频教程来自加州大学伯克利分校。它实际上是一个简单的概念。如果你听到教授Shewchuck(又名神级教师)解释它,你会说:“哦,这就是全部了!”。

我发现了大约尤其是对一个人谁没有太多成数学大O符号一个真正伟大的解释。

的https:// rob- bell.net/2009/06/a-beginners-guide-to-big-o-notation/

  

大O符号是计算机科学用于描述性能   或算法的复杂性。大O具体地说明   最坏的情况下,可以用来描述执行时间   需要或空间通过使用(例如在存储器中或磁盘上)   算法

     

任何谁的读取编程珍珠或任何其他计算机科学   书籍,没有在数学接地将有碰了壁   当他们到达提及Ô章(N日志N)或其他看似   疯狂的语法。希望这篇文章将帮助你获得的   大O和对数的基础知识的理解。

     

作为一个程序员第一和第二数学家(或可能第三或   第四),我发现,了解大O彻底是最好的方式   产生代码的一些例子。所以,下面是一些常见的订单   与说明书和实施例沿生长在可能的情况。

     

O(1)

     

O(1)描述了一种算法,该算法将总是在同时执行   (或者空间),而不管所述输入数据集的大小的。

bool IsFirstElementNull(IList<string> elements) {
    return elements[0] == null; } O(N)
     

O(N)

     

O(N)描述了一种算法,其性能将线性增长和   正比于输入数据集的大小。这个例子   下面还演示了大O是如何支持最坏情况下的性能   场景;匹配的字符串可能的任何迭代过程中发现   对于循环和功能会提前返回,但大O符号将   总是假设上限其中算法将执行   最大迭代次数。

bool ContainsValue(IList<string> elements, string value) {
    foreach (var element in elements)
    {
        if (element == value) return true;
    }

    return false;
} 
     

O(N 2

     

O(N 2 )表示的算法,其性能是直接   正比于输入数据集的大小的平方。这是   共同与涉及嵌套迭代过来的数据的算法   组。更深的嵌套迭代将导致O(N 3 ),O(N 4 )等

bool ContainsDuplicates(IList<string> elements) {
    for (var outer = 0; outer < elements.Count; outer++)
    {
        for (var inner = 0; inner < elements.Count; inner++)
        {
            // Don't compare with self
            if (outer == inner) continue;

            if (elements[outer] == elements[inner]) return true;
        }
    }

    return false;
}
     

O(2 Ñ

     

O(2 Ñ)表示的算法其生长与每个additon到加倍   输入数据集。的O的生长曲线(2 Ñ)函数是   指数 - 出发很浅,然后meteorically上升。一个   例如O(2 Ñ)函数是斐波那契的递归计算   数:

int Fibonacci(int number) {
    if (number <= 1) return number;

    return Fibonacci(number - 2) + Fibonacci(number - 1);
}
     

对数

     

对数稍微棘手的解释,所以我将使用一个通用   例如:

     

二进制搜索是用于搜索排序数据集的技术。有用   通过选择数据组的中间元件,基本上与   中位数,并确定它的目标值。如果值匹配它   将返回成功。如果目标值比的值越高   探针元件将需要该数据集的上半部分和   对其执行相同的操作。同样地,如果目标值   低于探针元件的值,其将执行的   针对下半部操作。它将继续减半数据   在每次迭代或设置,直到该值已被发现,直到它可以   不再被划分的数据组。

     

此类型的算法被描述为为O(log N)。迭代减半   在二分搜索中描述的数据集的产生生长   曲线的峰在开始慢慢变平的大小   数据集增加例如含有10个项目的输入数据集   需要一秒钟内完成,含有100个项目的数据集需要   两秒钟,含有1000个项目的数据集需要三   秒。斗bling的所述输入数据集的大小具有影响不大   其作为算法的单次迭代中的数据集后的生长   将与输入数据集被减半,并且因此相提并论一半   尺寸。这使得像二进制搜索算法非常有效的   大型数据集的时候。

这是一个很简单的解释,但我希望它涵盖了最重要的细节。

让我们说你的算法处理这个问题取决于一些“因素”,例如让我们把它N和X。

根据N和X,你的算法需要一些操作,例如在最坏的情况下,它3(N^2) + log(X)操作。

由于大O不会太在意常数因子(又名3),你的算法的大O是O(N^2 + log(X))。它基本上翻译“操作的算法需要为最坏的情况下,量与此秤”。

前言

算法:程序/式解决问题


如何分析算法和我们如何可以比较的算法对每一个其他的?

例如: 你和你的朋友是要求创建一个函数总数,从0到N你来了f(x)和你的朋友来了g(x)。这两个职能相同的结果,但不同算法。为了客观地比较效率的算法我们使用 大O符号.

大O符号: 描述 如何快速的运行时间将增长相对于输入与输入得到任意大。

3的关键内容:

  1. 比较 如何快速的运行时增长 比较确切的运行时 (取决于硬件)
  2. 只关心运行时增长相对于输入 (n)
  3. 作为 n 被任意大,重点放在该条款将增长最快的为n获取大(觉得无限)的AKA 渐近的分析

空间复杂性: 除了时间的复杂性,我们也关心关于空间复杂(有多少内存/空间的一个算法的使用).而不是检查时的行动,我们检查的大小分配的存储器。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top