我希望尽可能少用正式的定义和簡单的数学方法
不确定我是否会进一步为该主题做出贡献,但仍想与我分享:我曾经发现对Big O给出了一些非常有用的(虽然很基本的)解釋和示例:
通过示例这有助于将裸露的基础知识带入我的to壳般的头骨,所以我认为阅读这本书要花10分钟以使您朝正确的方向前进。
Big O的簡单英语解释是什么 用尽可能少的形式定义和简单的数学方法。
需要大O标记的简单英语解释:
当我们编程时我们正在尝试解决问题。 峩们编写的代码称为算法 大O表示法使我们能够以标准化方式比较算法最差情况的性能。 硬件规格随时间变化硬件的改进可以减少算法運行所需的时间。 但是更换硬件并不意味着我们的算法会随着时间的推移而有所改善或改进因为我们的算法仍然相同。 因此为了使我們能够比较不同的算法,以确定一个算法是否更好我们使用Big O表示法。
什么大O符号的纯英文的解释是:
并非所有算法都在相同的时间内运荇并且可能会根据输入中的项数(我们称为n)而有所不同。 基于此我们考虑最坏情况的分析,或者随着n越来越大而增加运行时间 我們必须知道n是什么,因为许多Big O符号都引用了n
当x到达a(例如a = +∞)时, f (x)= O( g (x))表示存在一个函数k 使得:
k限制在a的某个邻域内(如果a = +∞,则意味着存在数字N和M使得对于每个x> N,| k (x)| <M)
换句话说,用简单的英语来说: f (x)= O( g (x))x→a,意味着在a的附近 f分解为g和某些囿界函数的乘积。
顺便说一下这里是为了比较小o的定义。
f (x)= o( g (x))当x到达一个意味着存在一个函数k时:
当x到达a时, k (x)变为0
注意! 等号“ =”的表示法使用“伪等于”:o(g(x))= O(g(x))是正确的,但O(g(x))= o(g (X)) 类似地,可以在x→+∞时写下“ ln(x)= o(x)”泹是公式“ o(x)= ln(x)”将毫无意义。
当n→+∞时O(1)= O(n)= O(n 2 )(但反之,相等是“伪”)
算法示例(Java):
该算法逐项搜索列表,寻找关鍵字
对列表中的每个项目进行迭代(如果是键名),然后返回True
如果循环结束而找不到键,则返回False
Big-O表示复杂度的上限(时间,空间..)
要找到关于时间复杂性的Big-O:
计算最坏情况需要花费多少时间(关于输入大小):
最坏情况:密钥在列表中不存在。
最佳情况:关键是第┅项
时间(最佳情况)= 4
时间:Ω(4)= O(1)?瞬时\\恒定
衡量软件程序的速度非常困难,并且当我们尝试时答案可能非常复杂,并且充满叻异常和特殊情况 这是一个大问题,因为当我们想将两个不同的程序相互比较以找出哪个是“最快的”时所有这些例外和特殊情况都會使人分心并且毫无用处。
由于所有这些无用的复杂性人们试图使用最小和最小复杂度(数学)表达式来描述软件程序的速度。 这些表達式是非常粗略的近似值:尽管有些运气但它们可以捕捉到某个软件是快速还是慢速的“本质”。
由于它们是近似值因此在表达式中使用字母“ O”(大哦)作为惯例,以向读者表明我们在进行过度简化 (并确保没有人错误地认为该表达式无论如何都是正确的)。
如果您将“哦”读为“大约”或“大约”的意思那您就不会做错太多。 (我认为选择Big-Oh可能是一种幽默的尝试)
这些“ Big-Oh”表达式试图做的唯┅事情是描述随着我们增加软件必须处理的数据量而使软件速度降低多少。 如果我们将需要处理的数据量增加一倍那么该软件是否需要兩倍的时间才能完成工作? 十倍长 实际上,您会遇到非常有限的big-Oh表达式并且需要担心:
O(1)
常数 :无论输入多大,程序都需要花费相同的時间来运行
O(log n)
对数 :即使输入大小增加很多,程序运行时间也只会缓慢增加
O(n)
线性 :程序运行时间与输入大小成比例增加。
O(n^k)
多项式 :-处理時间增长得越来越快-作为多项式函数-随着输入大小的增加
O(k^n)
指数程序运行时非常迅速地增加,甚至问题的大小适度增加-仅适用于使用指数算法处理小的数据集
O(n!)
阶乘该程序的运行时间将比您等待不起最小且最琐碎的数据集所需的时间更长。
“ Big O的简单英语解释是什么用尽可能少的正式定义和简单的数学方法。 ”
这样一个漂亮而简单的简短问题似乎至少应该得到同样简短的答案就像学生在补习期间可能会收箌的一样。
Big O表示法仅根据输入数据的数量 **告诉您算法可以在多少时间内运行
(*在无单位的美好时光中!)
(**这很重要,因为无论今天还昰明天人们 )
好吧,如果这样做的话Big O标记的奇妙之处是什么?
实际上Big O分析是如此有用且重要,因为Big O将焦点直接放在算法自身的复杂喥上并且完全忽略了仅仅是比例常数的任何内容,例如JavaScript引擎CPU的速度,您的Internet连接以及所有这些很快变得像T型车一样可笑的过时的东西 Big O僅以对现在或将来的人们同样重要的方式关注绩效。
Big O表示法也直接聚焦于计算机编程/工程学最重要的原理这一事实激励着所有优秀的程序员继续思考和梦想:获得超越技术进步的成果的唯一途径是发明更好的技术。算法
假设我们正在谈论算法A ,该算法应该对大小为n的数據集执行某些操作
如果执行A时不走运,则可能需要多达X(n)个操作才能完成
碰巧,有一定的函数(把它们想象成X(n)的实现 )往往會经常发生。 这些是众所周知的很容易比较(示例: 1
, Log N
N
, N^2
N!
等。)
通过在讨论A和其他算法时比较这些算法可以轻松地根据算法可能需要 (最坏情况)完成的操作数对算法进行排名。
通常我们的目标是找到或构建算法A ,使其具有一个函数X(n)
该函数返回尽可能少的数字。
一个简单直接的答案可以是:
大O表示该算法的最坏可能的时间/空间 该算法绝不会占用超过该限制的更多空间/时间。 大O表示极端情况下嘚时间/空间复杂度
这是我在解释Big-O的常见变体时倾向于使用的简单的英语动物
在所有情况下,优先选择列表上方的算法而不是列表下方的算法 但是,转移到更昂贵的复杂性类别的成本差异很大
没有增长。 不管问题有多大您都可以在相同的时间内解决它。 这有点类似于廣播无论广播范围内的人数多少,在给定距离上广播都需要消耗相同数量的能量
这种复杂性与O(1)相同,只不过差一点点 出于所有實际目的,您可以将其视为非常大的恒定比例 处理1000个项目和10亿个项目之间的工作差异只有六分之一。
解决问题的成本与问题的大小成正仳 如果您的问题规模增加了一倍,那么解决方案的成本就会增加一倍 由于大多数问题都必须以某种方式扫描到计算机中,例如数据输叺磁盘读取或网络流量,因此通常这是一个负担得起的缩放因子
这种复杂性与O( n )非常相似。 出于所有实际目的两者是等效的。 这種复杂程度通常仍被认为是可扩展的 通过调整假设,可以将某些O( n log n )算法转换为O( n )算法 例如,限制键的大小可减少从O( n log n )到O( n )的排序
生长为正方形,其中n是正方形边的长度 这与“网络效应”的增长率相同,在网络效应中网络中的每个人都可能认识网络中的其怹每个人。 增长是昂贵的 如果不进行大量的体操练习,大多数可伸缩的解决方案就无法使用具有这种复杂性级别的算法 这通常也适用於所有其他多项式复杂度-O( n k ) -。
不缩放 您没有解决任何重要问题的希望。 对于了解要避免的内容以及专家找到O( n k )中的近似算法很有用
大O表示法是一种描述在给定数量的输入参数(称为“ n”)的情况下算法运行速度的方法。 它在计算机科学中很有用因为不同的机器以鈈同的速度运行,并且简单地说一个算法需要5秒钟并不能告诉您太多信息因为当您运行的系统带有4.5 GHz八核八核处理器时,我可能正在运行┅个15年的800 Mhz系统无论使用哪种算法,都可能需要更长的时间 因此,我们没有指定算法按时间运行的速度而是说按输入参数的数量(即“ n”)运行的速度。 通过以这种方式描述算法我们可以比较算法的速度,而不必考虑计算机本身的速度
我有一种更简单的方式来了解時间复杂度,他用于计算时间复杂度的最常用指标是Big O表示法 这消除了所有恒定因素,因此当N接近无穷大时可以相对于N估算运行时间。 通常您可以这样认为:
是不变的。 语句的运行时间不会相对于N改变
是线性的 循环的运行时间与N成正比。当N加倍时运行时间也成正比。
是二次方的 两个循环的运行时间与N的平方成正比。当N翻倍时运行时间增加N *N。
是对数的 该算法的运行时间与N可以除以2的次数成正比。这是因为该算法在每次迭代中将工作区域划分为一半
是N * log(N)。 运行时间由N个对数的循环(迭代或递归)组成因此该算法是线性和对數的组合。
通常对一维中的每个项目执行某项操作是线性的,对二维中每一个项目执行某项操作是二次项将工作区域分为两半是对数嘚。 还有其他大O度量例如立方,指数和平方根但它们并不常见。 大O表示法描述为O()这里的小数位数。 快速排序算法将描述为O(N * log(N))
注意:这些都没有考虑最佳,平均和最坏情况下的度量 每个都有自己的Big O表示法。 另请注意这是一个非常简单的解释。 大O是最常見的但是我已经展示过它更加复杂。 还有其他符号例如大欧米茄,小o和大theta 在算法分析课程之外,您可能不会遇到它们
如果您头脑Φ有一个合适的无穷大概念,则有一个非常简短的描述:
大O表示法告诉您解决无限大问题的成本
如果您升级到能够以两倍快的速度运行算法的计算机,则大的O表示法不会注意到这一点 恒定因子的改进太小,以至于无法在大O表示法适用的规模上注意到 请注意,这是大O符號设计的有意部分
尽管可以检测到“大于”恒定因子的任何值。
当有兴趣进行大小“大”到足以被视为近似无穷大的计算时则大的O标記大约是解决问题的成本。
如果上述没有意义那么您的脑海中就没有兼容的直觉概念,您可能应该忽略上述所有内容; 我知道要使这些想法变得严格或者如果它们在直观上还不实用的话,对它们进行解释的唯一方法是首先教给您大的O表示法或类似的东西 (尽管,一旦您将来很好地理解了大的O表示法可能有必要重新审视这些想法)
最简单的查看方式(用英语)
我们正在尝试查看输入参数的数量如何影響算法的运行时间。 如果您的应用程序的运行时间与输入参数的数量成正比则称其为n的BigO。
以上陈述是一个好的开始但并非完全正确。
哽准确的解释(数学的)
T(n)=表示算法运行时间为n的函数的实际函数
f(n)=一个近似函数将算法的运行时间表示为n的函数
那么就大O而言,呮要满足以下条件近似值f(n)就被认为足够好。
当n接近无穷大时n的T小于或等于n的c乘以f。
这被读为n的T在n的大O中
根据上面的数学定义,洳果您说算法是n的Big O则表示它是n(输入参数的数量) 或更快速的函数。 如果您的算法是n的Big O那么它也自动是n平方的BigO。
n的大O表示我的算法至尐运行速度与此相同 您无法查看算法的Big O符号并说出它的速度慢。 您只能说得很快
请查看 ,以获得来自UC Berkley的Big O视频教程 这实际上是一个简單的概念。 如果您听到Shewchuck教授(又名神级老师)对此进行了解释您会说:“哦,就是这样!”
大O表示法是一种根据空间或运行时间来描述算法上限的方法。 n是问题中元素的数量(即数组的大小树中节点的数量等)。我们有兴趣描述n变大时的运行时间
当我们说某种算法昰O(f(n))时,我们说的是该算法的运行时间(或所需空间)始终小于某些恒定时间f(n)
说二进制搜索的运行时间为O(logn)就是说存在一個常数c,您可以将log(n)乘以常数c该常数将始终大于二进制搜索的运行时间。 在这种情况下您总是会有一些常数的log(n)比较。
换句话说其中g(n)是算法的运行时间,我们说g(n)= O(f(n))当g(n)<= c * f(n)时,n> k其中c和k是一些常数。
这是一个非常简化的解释但我希望它涵盖叻最重要的细节。
假设您处理问题的算法取决于某些“因素”例如,让它成为N和X
根据N和X,您的算法将需要一些运算例如,在最坏的凊况下它是3(N^2) + log(X)
运算。
由于Big-O不太关心常数因子(aka 3)因此算法的Big-O为O(N^2 + log(X))
。 它基本上可以翻译为“算法在最坏情况下所需的运算量”
假设您从亚馬逊订购了《哈利·波特:完整的8电影集》 [Blu-ray],并同时在线下载了同一部电影集 您想测试哪种方法更快。 交付将花费几乎一天的时间下載大约提前30分钟完成。 大! 所以这是一场激烈的比赛
如果我订购了几部蓝光电影,例如《指环王》《暮光之城》,《黑暗骑士三部曲》等并同时在线下载所有电影,该怎么办 这次,交付仍需要一天的时间才能完成但是在线下载需要3天才能完成。 对于在线购物购買物品(输入)的数量不影响交货时间。 输出是恒定的 我们称其为O(1) 。
对于在线下载下载时间与电影文件大小(输入)成正比。 我們称其为O(n)
通过实验,我们知道在线购物的规模要比在线下载更好 理解大O表示法非常重要,因为它可以帮助您分析算法的可伸缩性囷效率
注意:大O表示法表示算法的最坏情况 。 假设O(1)和O(n)是以上示例的最坏情况
您想知道所有有关大O的知识吗? 我也是
因此,談到大O我将使用其中只有一个节拍的单词。 每个字一个声音 小字很快。 您知道这些单词我也知道。我们将使用一种声音的单词 他們很小。 我相信您会知道我们将使用的所有词语!
现在让您和我谈谈工作。 大多数时候我不喜欢工作。 你喜欢工作吗 您可能会这样莋,但是我确定我不会
我不喜欢上班。 我不喜欢花时间在工作上 如果可以,我只想玩做一些有趣的事情。 你有和我一样的感觉吗
現在有时候我必须去上班。 这是可悲的但却是事实。 因此在工作时,我有一条规则:我尝试减少工作量 我几乎没有工作。 然后我去玩!
所以这是个大新闻:大O可以帮助我不做工作! 如果我知道大O我可以更多时间玩游戏。更少的工作更多的游戏! 这就是大O帮我做的。
现在我有一些工作 我有此列表:1、2、3、4、5、6。 我必须在此列表中添加所有内容
哇,我讨厌工作 但是,哦我必须这样做。 所以我赱了
一加二等于三……加三等于六……而四等于……我不知道。 我迷路了 我脑子里很难做。 我不太喜欢这种工作
所以,我们不做这項工作 让您和我一起思考这有多难。 加六个数字我需要做多少工作?
好吧走着瞧。 我必须添加一个和两个然后将其添加到三个,嘫后将其添加到四个……总共我算了六个添加。 我必须做六个加法来解决这个问题
大O来了,告诉我们这个数学有多难
大O说:我们必須做六个加法来解决这个问题。 一加每件事从一到六。 六个小工作……每一工作都是一个加法
好吧,我现在不做添加工作 但是我知噵这会有多困难。 这将是六个添加
哦,不现在我还有更多工作要做。 嘘 谁制造这种东西?
现在他们要我加一到十! 我为什么要这么莋 我不想加一到六。 要从一增加到十……好吧……那将更加困难!
会有多困难 我还要做多少工作? 我需要更多或更少的步骤吗
好吧,我想我将不得不做十个加法...每件事从一到十 十等于六。 我必须付出更多的努力才能从一增加到十而不是一到六个!
我现在不想添加。 我只想考虑添加那么多有多困难 而且,我希望能尽快玩
要从一增加到六,这是一些工作 但是,您看到从一增加到十还有更多工莋要做吗?
大O是你的朋友也是我的朋友。 大O帮助我们思考我们需要做多少工作以便我们可以计划。 而且如果我们是大O的朋友,他可鉯帮助我们选择不那么困难的工作!
现在我们必须做新工作 不好了。 我一点都不喜欢这个工作
新工作是:将所有事物从一加到n。
等待! 什么是n 我想念吗? 如果您不告诉我n是什么我怎么能从n加到n?
好吧我不知道n是什么。 没有告诉我 是你吗 没有? 那好吧 所以我们鈈能做工作。 ew
但是,尽管我们现在不做这项工作但是如果知道n,我们可以猜测会有多困难 我们必须累加n个东西,对不对 当然!
现茬是大O,他将告诉我们这项工作有多么艰辛 他说:将所有事物从一加一到N就是O(n)。 要添加所有这些内容[我知道我必须加n次。] [1]真是个夶王! 他告诉我们做某种工作有多困难
对我而言,我认为大O就像一个又大又慢的老板人 他考虑工作,但他没有做 他可能会说:“那笁作很快。” 或者他可能会说:“工作是如此缓慢而艰辛!” 但是他不做这项工作。 他只看工作然后告诉我们可能要花多少时间。
我非常喜欢大O为什么? 我不喜欢工作! 没有人喜欢工作 这就是为什么我们都喜欢大O! 他告诉我们我们可以工作多快。 他帮助我们想到了艱苦的工作
嗯,还有更多工作 现在,让我们不做这项工作 但是,让我们逐步制定一个计划
他们给了我们十张纸牌。 他们混在一起:七个四个,两个六个……根本不是直线。 现在...我们的工作是对它们进行排序
恩 这听起来像很多工作!
我们如何分类这个牌组? 我囿个计划
我将从头到尾逐一查看每副牌。 如果一对中的第一张大而另一对中的第二张小,我将其交换 否则,我转到下一对依此类嶊……不久,甲板就完成了
甲板结束后,我问:那张卡中是否交换了卡片 如果是这样,我必须从头再做一次
在某个时候,某个时候将不会进行任何交换,而我们的工作将完成 这么多工作!
那么,按照这些规则对卡片进行排序将需要做多少工作
我有十张卡。 而且在大多数情况下-如果我运气不佳-我必须遍历整个卡座多达十次,每次通过卡座最多要交换十张卡
大O进来说:对于一副n张牌,以这种方式排序将在O(N平方)时间内完成
好吧,你知道n的平方是n乘以n 现在,我明白了:检查了n张卡最多可能经过了甲板n次。 那是两个循环烸个循环有n个步骤。 那是很多工作要做的平方 当然,很多工作!
现在当大O表示需要O(n平方)的工作时,他并不意味着n平方相加 在某些情况下,可能会少一些 但在最坏的情况下,对平台进行分类将需要接近n个平方的工作步骤
现在在这里,大O是我们的朋友
Big O指出了这┅点:随着n变大,当我们对卡片进行排序时该工作将比旧的“仅添加这些东西”的工作困难得多。 我们怎么知道呢
好吧,如果n真的变夶我们不在乎我们可能会增加n或n平方的值。
对于大nn平方比n大。
大O告诉我们对事物进行排序比对事物进行添加更为困难。 对于大nO(n岼方)大于O(n)。 这意味着:如果n变大则对n个混合对象进行排序必须比添加n个混合对象花费更多的时间。
大O不能解决我们的工作 大O告訴我们工作有多艰辛。
我有一副纸牌 我对它们进行了排序。 你帮了 谢谢
有没有更快速的方法来分类卡片? 大澳可以帮助我们吗
是的,有一种更快的方法! 它需要一些时间来学习但是它可以工作……而且工作非常快。 您也可以尝试但要花一些时间在每一步上,不要夨去自己的位置
在这种分类卡片组的新方式中,我们不会像前一段时间那样检查成对的牌 这是排序此套牌的新规则:
一:我在我们现茬正在使用的套牌中选择一张牌。 如果愿意可以为我选择一个。 (当然这是我们第一次进行此操作,“现在我们正在处理的部分甲板”是整个甲板)
二:我张开了你选择的那张牌的底牌。 这是什么八卦 我如何展开 好吧,我从起始卡开始一个接一个地寻找并且寻找仳八字卡更高的卡。
三:我从末尾卡开始然后寻找比八字卡低的卡。
找到这两张卡后我将其交换,然后继续寻找更多可交换的卡 也僦是说,我返回到第二步并在您选择的卡上展开。
在某个时候这个循环(从2到3)将结束。 当搜索的两半都在相纸卡上相遇时它结束。 然后我们用您在第一步中选择的卡张开了甲板。 现在开始附近的所有牌都比八字牌低。 并且末尾的牌比八字牌高 酷把戏!
四个(這是有趣的部分):我现在有两个小牌组,一个比八字卡低另一个高。 现在我要在每个小平台上执行第一步! 就是说,我从第一个小岼台上的第一步开始完成这项工作后,我从下一个小平台上的第一步开始
我将甲板分解成几个部分,然后对每个部分进行分类每个蔀分越来越小,有时我没有更多工作要做 现在,按照所有规则这似乎很慢。 但是请相信我这一点都不慢。 它比第一种分类方法要少嘚多!
这种叫什么呢 这就是所谓的快速排序! 这种排序是由一个叫 ,他称它为Quick Sort 现在,快速排序一直被使用!
快速排序将大牌分解成小爿 也就是说,它可以将大任务分解成小任务
嗯 我认为那里可能有一条规则。 要使大型任务变小请将其分解。
这种排序非常快 多快 Big O告诉我们:在这种情况下,这种工作需要O(n log n)来完成
它比第一类快多少? 大O请帮忙!
第一类是O(n平方)。 但是快速排序是O(n log n) 您知噵n log n小于n平方,对于大n吧 好吧,这就是我们知道快速排序的速度!
如果您必须分类套牌最好的方法是什么? 好吧您可以做您想做的事,但是我会选择“快速排序”
为什么选择快速排序? 我当然不喜欢工作! 我希望尽快完成工作
我怎么知道快速排序的工作量少? 我知噵O(n log n)小于O(n平方) O的尺寸较小,因此“快速排序”的工作量较小!
现在您认识了我的朋友BigO他帮助我们减少了工作量。 而且如果您知道大O,也可以减少工作量!
你从我身上学到了所有! 你真聪明! 非常感谢!
现在工作已经完成让我们开始吧!
[1]:有一种方法可以一次性欺骗所有事物并将其从n添加到n。 一个叫高斯的孩子八岁时就发现了这一点 我虽然不那么聪明,所以
我发现了有关大O表示法的很好的解释,特别是对于一个数学不多的人
Big O符号在计算机科学中用于描述算法的性能或复杂性。 Big O特别描述了最坏的情况可用于描述算法所需嘚执行时间或使用的空间(例如,内存或磁盘)
读过Programming Pearls或任何其他计算机科学书籍且没有数学基础的任何人,在到达提及O(N log N)或其他看似瘋狂的语法的章节时都会碰壁 希望本文能帮助您了解Big O和对数的基础。
作为程序员的第一位然后是数学家的第二位(或者也许是第三位戓第四位),我发现透彻理解Big O的最佳方法是编写一些示例代码 因此,以下是一些常见的增长顺序以及可能的描述和示例
O(1)描述了一種算法,无论输入数据集的大小如何该算法将始终在同一时间(或空间)执行。
O(N)描述了一种算法其性能将线性增长,并且与输入數据集的大小成正比 下面的示例还演示了Big O如何支持最坏情况下的性能情况; 在for循环的任何迭代期间都可以找到匹配的字符串,并且该函數将尽早返回但是Big O表示法将始终假定算法将执行最大迭代次数的上限。
O(N 2 )表示一种算法其性能与输入数据集的大小的平方成正比。 這在涉及对数据集进行嵌套迭代的算法中很常见 更深层的嵌套迭代将导致O(N 3 ),O(N 4 )等
O(2 N )表示一种算法,每增加一个输入数据集其增长量就会增加一倍。 O(2 N )函数的增长曲线是指数的-从非常浅的位置开始然后在气象上上升。 O(2 N )函数的一个示例是斐波那契数的递歸计算:
对数解释起来有些棘手因此我将使用一个常见示例:
二进制搜索是一种用于搜索排序的数据集的技术。 它通过选择数据集的中間元素(实际上是中位数)进行工作并将其与目标值进行比较。 如果值匹配它将返回成功。 如果目标值高于探针元素的值它将获取數据集的上半部分并对其执行相同的操作。 同样如果目标值低于探针元素的值,它将对下半部分执行操作 在每次迭代之前,它将继续將数据集减半直到找到该值或无法再拆分数据集为止。
这种算法称为O(log N) 二元搜索示例中描述的数据集的迭代减半生成一条增长曲线,该曲线在开始时达到峰值并随着数据集大小的增加而逐渐变平,例如包含10个项目的输入数据集需要一秒钟才能完成,一个数据集包含100个项目的数据将花费2秒而包含1000个项目的数据集将花费3秒。 将输入数据集的大小加倍对其增长几乎没有影响因为在算法的单次迭代后,数据集将减半因此与输入数据集大小的一半相等。 这使得诸如二进制搜索之类的算法在处理大型数据集时极为有效
算法 :解决问题嘚过程/公式
如何分析算法,以及如何相互比较算法
例如:您和您的朋友被要求创建一个将0到N的数字求和的函数。您得出f(x)而您的朋伖得出g(x)。 这两个函数具有相同的结果但算法不同。 为了客观地比较算法的效率我们使用Big-O表示法 。
Big-O表示法:描述当输入任意大时運行时相对于输入的增长速度。
空间复杂度:除了时间复杂度外,我们还关心空间复杂度(算法使用哆少内存/空间) 我们不检查操作时间,而是检查内存分配的大小
Big O只是一种以一种常见的方式“表达”自己的方式,即“运行我的代码需要多少时间/空间”。
您可能经常看到O(n)O(n 2 ),O(nlogn)等所有这些只是显示方式; 算法如何变化?
O(n)表示Big O为n现在您可能会想,“ n!”是什么 那么“ n”是元素的数量。 要在阵列中搜索项目的映像 您将不得不查看每个元素,并将其显示为“您是否正确的元素/项目” 在最坏的情况下,该项目位于最后一个索引处这意味着它花费的时间与列表中的所有项目一样多。因此一般来说,我们说“哦嘿,n是一个给定的值!”
因此,您可能会理解“ n 2 ”的含义但更具体地讲,请您以为您拥有简单最简单的排序算法; 泡泡糖 该算法需偠仔细检查每个项目的整个列表。
这是O n 2,因为您需要查看列表中所有包含“ n”个项目的项目 对于每个项目,您再次查看所有项目以进行比较,这也是“ n”因此对于每个项目,您查看“ n”次这意味着n * n = n 2
我希望这是您想要的那样简单。
但是请记住Big O只是一种以时间和空间方式表现自己的方式。
编辑:快速说明这几乎肯定会使 (这是一个上限)与Theta表示 (这是一个上下限)混淆。 以我的经验这实际上是非学术场合中讨论的典型内容。 造成任何混乱我们深表歉意。
一句话:随着工作规模的扩大完成工作需要多长时间?
显然这仅使用“大小”作为输入,洏使用“花费的时间”作为输出—如果您想谈论内存使用情况等也可以使用相同的想法。
这是一个示例其中我们有N件T恤要干燥。 我们假定将它们置于干燥位置非常快(即与人的互动可以忽略不计)。 当然现实生活中并非如此...
在室外使用清洗线:假设您有无限大的后院,则清洗会在O(1)时间内烘干 无论您拥有多少,它都会得到相同的阳光和新鲜空气因此大小不会影响干燥时间。
使用滚筒式干衣机:每次装载10件衬衫一个小时后完成。 (忽略此处的实际数字它们是无关紧要的。)因此烘干50件衬衫所需的时间大约是烘干10件衬衫所需时间的5倍。
将所有物品放到通风的橱柜中:如果将所有物品放到一大堆中并让整体保暖中衬衫要花很长时间才能变干。 我不想猜测细節但我怀疑这至少是O(N ^ 2)-随着洗涤量的增加,干燥时间增加得更快
“大O”表示法的一个重要方面是,它并未说明哪种算法在给定大小丅会更快 拿一个哈希表(字符串键,整数值)和一个对数组(字符串整数)。 根据字符串在哈希表中查找键或在数组中查找元素是否哽快 (即对于数组,“在字符串部分与给定键匹配的地方找到第一个元素”)哈希表通常被摊销(?=“平均”)O(1)—一旦建立,就應该花费大约同时在100条目表中查找条目的时间与在1,000,000条目表中查找条目的时间相同 在数组中找到一个元素(基于内容而不是索引)是线性嘚,即O(N)-平均而言您将不得不查看条目的一半。
这会使哈希表比查找数组快吗 不必要。 如果条目的集合很小则数组可能会更快-您鈳以在计算所要查找的哈希码所需的时间内检查所有字符串。 但是随着数据集的增大,哈希表最终将击败该数组
快速说明,这几乎肯萣会使 (上限)与Theta表示法“Θ”(两侧界线)混淆。 以我的经验,这实际上是非学术场合中讨论的典型内容。 造成任何混乱,我们深表歉意。
此图可以直观地显示O的复杂性:
我可以为Big-O表示法给出的最简单定义是:
Big-O表示法是算法复杂度的相对表示
该句子中有一些重要的和故意选择的单词:
- 相对的:您只能将苹果与苹果进行比较。 您无法将进行算术乘法的算法与对整数列表进行排序的算法进行比较 但是,对兩种进行算术运算的算法进行比较(一次乘法一次加法)将告诉您一些有意义的事情。
- 表示形式: Big-O(以最简单的形式)将算法之间的比較简化为单个变量 该变量是根据观察或假设选择的。 例如通常基于比较操作(对两个节点进行比较以确定它们的相对顺序)比较排序算法。 这假定比较是昂贵的 但是,如果比较便宜但交换昂贵呢 它改变了比较; 和
- 复杂性:如果我花一秒钟来排序10,000个元素,我要花多长時间来排序一百万个元素 在这种情况下,复杂性是相对于其他事物的相对度量
阅读完其余内容后,请重新阅读以上内容
我能想到的Big-O朂好的例子是算术。 取两个数字(123456和789012) 我们在学校学到的基本算术运算是:
这些都是操作或问题。 解决这些问题的方法称为算法
加法昰最简单的。 您将数字排列在右边(右边)并将数字添加到写有该结果的最后一个数字的列中。 该数字的“十”部分将结转到下一列
假设这些数字的加法是该算法中最昂贵的操作。 完全有理由将这两个数字相加我们必须将6个数字相加(可能带有7位)。 如果我们将两个100位数相加则必须相加100。 如果我们将两个 10,000位数字相加则必须进行10,000次加法。
看到图案了吗 复杂度 (即操作数)与较大数字中的位数n成正仳。 我们称其为O(n)或线性复杂度
减法类似(除非您可能需要借用而不是进位)。
乘法是不同的 您将数字排列起来,取下位数的第一個数字然后与上位数的每个数字依次相乘,依此类推 因此,要将我们的两个6位数相乘我们必须进行36次相乘。 我们可能需要做多达10个戓11列合计得到最终的结果了
如果我们有两个100位数字,则需要进行10,000次乘法和200次加法 对于两个一百万个数字,我们需要进行一万亿(10 12 )乘法和200万加法
随着算法按n 平方缩放,这就是O(n 2 )或二次复杂度 现在是引入另一个重要概念的好时机:
我们只关心复杂性的最重要部分。
機敏的人可能已经意识到我们可以将操作数表示为:n 2 + 2n 但是,正如您从我们的示例中看到的那样每个例子中有两个百万位数字,第二项(2n)变得微不足道(占该阶段总操作数的0.0002%)
可以注意到,我们在这里假设了最坏的情况 在将6位数字相乘时,如果其中之一具有4位数芓而另一个具有6位数字,则我们只有24个乘法 尽管如此,我们仍会计算该n的最坏情况即当两者均为6位数字时。 因此Big-O表示法是关于算法的最坏情况。
我能想到的下一个最佳示例是电话簿通常称为“白页”或类似内容,但因国家/地区而异 但是我说的是按姓氏,名字首芓母或名字可能的地址和电话号码列出的人。
现在如果您指示计算机在包含1,000,000个名字的电话簿中查找“ John Smith”的电话号码,您将怎么办 忽畧了一个事实,即您可以猜测S的开始距离(假设您不能)那么您会怎么做?
一个典型的实现方式可能是打开中间位置占据第500,000 个位置并將其与“ Smith”进行比较。 如果碰巧是“史密斯约翰”,我们真的很幸运 “ John Smith”更可能在该名称之前或之后。 如果是后我们再划分电话簿的後半对半重复动作。 如果在此之前那么我们将电话簿的前半部分分成两半,然后重复 等等。
这就是所谓的二进制搜索 并且每天都茬使用的编程你是否意识到这一点。
因此如果您想在一百万个电话簿中找到一个名字,则最多可以执行20次实际上可以找到任何名字。 茬比较搜索算法时我们认为此比较是我们的“ n”。
- 对于3个名字的电话簿最多需要进行2个比较。
那真是太好了不是吗?
在大澳而言這是O(log n)的或对数的复杂性 。 现在所讨论的对数可以是ln(底数e)log 10 ,log 2或其他一些底数 就像O(2n 2 )和O(100n 2 )都是O(n 2 )一样,它仍然是O(log n)
在這一点上,有必要解释一下Big O可用于通过一种算法确定三种情况:
- 最佳情况:在电话簿搜索中,最佳情况是我们在一次比较中找到了姓名 这是O(1)或不变的复杂度 ;
- 预期情况:如上所述,这是O(log n); 和
- 最坏的情况:这也是O(log n)
通常情况下,我们不关心最好的情况 我们对預期和最坏的情况感兴趣。 有时这些中的一个或更重要
如果您有电话号码并想要找到姓名怎么办? 警方有一个反向电话簿但这样的查找窗口被剥夺了广大市民 还是他们? 从技术上讲您可以在普通电话簿中反向查找号码。 怎么样
你开始在名字和比较的数量。 如果这是┅场比赛那很好,如果不是那您就进入下一个。 您必须采用这种方式因为电话簿是无序的 (无论如何都按电话号码排序 )。
因此根据电话号码查找姓名(反向查找):
- 最佳情况: O(1);
- 最坏的情况: O(n)(代表1,000,000)。
这是计算机科学中一个非常著名的问题值得一提。 茬这个问题上您有N个城镇。 这些城镇中的每个城镇都通过一定距离的道路链接到一个或多个其他城镇 旅行推销员的问题是找到访问每個城镇的最短行程。
听起来很简单 再想一想。
如果您有3个镇AB和C,所有对之间都有道路那么您可以去:
好吧,实际上还不止这些因為其中一些是等效的(例如,A→B→C和C→B→A是等效的因为它们使用相同的道路,只是反向)
实际上,有3种可能性
- 将其带到4个城镇,您囿(iirc)12种可能性
这是称为阶乘的数学运算的函数。 基本上:
因此旅行推销员问题的Big-O是O(n!)或阶乘或组合复杂度 。
到200个城镇时宇宙Φ没有足够的时间来解决传统计算机的问题。
我想快速提及的另一点是任何具有O(n a )复杂度的算法都被认为具有多项式复杂度或在多项式时间内可解。
O(n)O(n 2 )等都是多项式时间。 有些问题不能在多项式时间内解决 因此,世界上使用了某些东西 就是一个很好的例子。 在计算上很难找到数量很大的两个主要因素 如果不是,我们将无法使用所使用的公钥系统
无论如何,这就是我对Big O(修订本)的解释(希望是纯英语)
大O表示算法使用多少时间/空间(相对于其输入大小)。
如果算法为O(n)则时间/空间将以与其输入相同的速率增加。
洳果算法为O(n 2 )则时间/空间将以其输入平方的速率增加。
大O描述了当输入变大时函数的增长行为(例如程序的运行时)的上限
O(n):洳果我将输入大小加倍,则运行时间将加倍
O(n 2 ):如果输入大小加倍运行时间四倍
O(log n):如果输入大小加倍则运行时间增加一
O(2 n ):如果输入大小增加一,则运行时会加倍
输入大小通常是表示输入所需的空间(以位为单位)
它显示了算法如何根据输入大小进行缩放。
O(n 2 ) :称为二次复杂度
请注意项目数增加了10倍,但时间增加了10 2倍 基本上,n = 10所以O(n 2 )给我们缩放因子n 2 ,它是10 2
O(n) :称为线性复杂度
这佽,项目数增加了10倍时间也是如此。 n = 10因此O(n)的比例因子为10。
O(1) :称为恒定复杂度
项目数量仍在增加10倍但是O(1)的缩放比例始终為1。
O(log n) :称为对数复杂度
计算数量仅增加输入值的对数 因此,在这种情况下假设每次计算花费1秒,则输入n
的对n
就是所需的时间因此为log n
。
这就是要旨 他们降低了数学运算的精度,因此可能不是正好是n 2或他们所说的那样但这将是缩放的主要因素。
大O描述了算法的基夲缩放性质
Big O并没有告诉您很多关于给定算法的信息。 它切开了骨头仅提供有关算法可缩放性的信息,特别是响应“输入大小”算法的資源使用(思考时间或内存)如何缩放
考虑一下蒸汽机和火箭之间的区别。 它们不仅是同一事物的不同变体(例如普锐斯(Prius)引擎还是蘭博基尼(Lamborghini)引擎)而且它们的核心是截然不同的推进系统。 蒸汽机可能比玩具火箭快但是没有蒸汽活塞机能够达到轨道运载火箭的速度。 这是因为这些系统在达到给定速度(“输入大小”)所需的燃料(“资源使用”)的关系方面具有不同的缩放特性
为什么这个这麼重要? 因为软件处理的问题的大小差异可能高达一万亿美元 考虑一下。 登月所需的速度与人的行走速度之间的比小于10,000:1与软件可能媔对的输入大小范围相比,这绝对很小 而且由于软件的输入大小可能面临天文数字范围,因此算法的Big O复杂性(其基本的伸缩性)可能胜過任何实现细节
考虑规范的排序示例。 冒泡排序为O(n 2 )而合并排序为O(n log n)。 假设您有两个排序应用程序使用气泡排序的应用程序A和使用合并排序的应用程序B,假设输入大小约为30个元素则应用程序A在排序时比应用程序B快1000倍。 如果您不必排序多于30个元素那么显然您应該首选应用程序A,因为在这些输入大小下它要快得多 但是,如果您发现可能必须分类一千万个项目那么您期望的是,在这种情况下應用程序B实际上最终比应用程序A快数千倍,这完全是由于每种算法的扩展方式所致
英文对“ Big O”符号的解释是什么?
“大O”中的O称为“顺序”(或恰好是“ ...的顺序”)
因此您可以从字面上理解它的想法即它用于订购某些东西以进行比较。
1
步这是非常好的,有序一号
logN
步骤完成任务,良好已订购2号
N
步骤完成任务公平,第3号命令
O(NlogN)
步骤结束任务,不好第4号命令
N^2
步骤完成任务很糟糕,第5号订单
2^N
步骤完成任务,这太可怕了第6号命令
N!
完成任务N!
步骤太糟糕了,第7号订单
假设您嘚到符号O(N^2)
不仅您清楚该方法需要N * N个步骤来完成一项任务,而且从其排名来看它还不如O(NlogN)
好。
请注意行尾的顺序以方便您更好地理解。洳果考虑所有可能这里有7种以上的符号。
在CS中完成任务的步骤集称为算法。
在术语中Big O表示法用于描述算法的性能或复杂性。
另外Big O確定最坏情况或测量上限步。
您可以参考Big-Ω(Big-Omega)以获得最佳情况
“大O”描述算法的性能并对其进行评估。
或正式解决这个问题“大O”對算法进行分类并标准化比较过程。
当您忽略恒定因素和原点附近的东西时 Big-O表示法(也称为“渐近生长”表示法)的作用是“看起来像” 。 我们用它来谈论事物如何扩展
用于“足够”的大投入...
big-O表示法不关心常量因素:函数9x?
据说“完全像10x?
一样增长”。 big-O 渐近符号也不关惢非渐近的东西(“原点附近的东西”或“问题大小较小时会发生什么”):函数10x?
被称为“完全像10x? - x + 2
一样增长”
您为什么要忽略方程式的较小部分? 因为当您考虑越来越大的比例时它们变得与方程的大部分完全相形见;; 他们的贡献变得微不足道且无关紧要。 (请参阅礻例部分)
换句话说,这是关于无限远的比率 如果将实际花费的时间除以O(...)
,您将在大输入量的限制中得到一个常数 直观上讲,这是囿道理的:如果您可以将一个函数相乘得到另一个函数则函数会彼此“缩放”。 那是当我们说...
...这意味着对于“足够大”的问题大小N (如果我们忽略原点附近的东西)存在一个常数(例如2.5,完全组成)使得:
────────────────────── < constant ───────────────────── < 2.5
常量有很多选择。 通常“最佳”选择被称为算法的“恒定因子”……但是我们经常忽略它,就像我們忽略非最大的项(有关为什么它们通常无关紧要请参见“恒定因子”部分)。 您还可以将上述等式视为一个边界说:“ 在最坏的情況下,所花费的时间永远不会比大约N*log(N)
差2.5倍以内(我们不愿不在乎) ”
通常, O(...)
是最有用的因为我们经常关心最坏的情况。 如果f(x)
表示“坏”的东西例如处理器或内存使用率,则“ f(x) ∈ O(upperbound)
”表示“ upperbound
是处理器/内存使用率的最坏情况”
作为纯粹的数学构造,big-O表示法不限于谈论处理時间和内存 您可以使用它来讨论有意义缩放的任何事物的渐近性,例如:
N
个人之间可能握手的数量( ?(N?)
特别是N(N-1)/2
,但重要嘚是它的缩放比例类似于N?
)
对于上面的握手示例房间中的每个人都与其他人握手。 在该示例中 #handshakes ∈ ?(N?)
。 为什么
稍微备份一下:握手的次数恰好是n-choose-2或N*(N-1)/2
(烸N个人握手N-1个其他人的握手,但是这种重复计算的握手次数除以2):
但是对于非常多的人,线性项N
相形见and并有效地使比率为0(在图表Φ:随着参与者数量的增加,对角线上的空框在总框上所占的比例会变小) 因此,缩放行为为order N?
或者握手次数“像N?一样增长”。
好像图表对角线上的空白框(N *(N-1)/ 2个复选标记)甚至没有(N 2个复选标记渐近)一样。
(与“普通英语”暂時偏离:)如果您想向自己证明这一点则可以对比率进行一些简单的代数运算,以将其分解为多个项( lim
表示“被认为是lim
的极限”如果忽略则忽略它)。您还没有看到它只是“ N非常大”的记法):
TL;博士:握手“的样子”的数量X 2这么多的大的值,如果我们写下的比例#握掱/ X 2事实上,我们并不需要确切地 X 2的握手甚至不露面在十进制中任意大一会儿
“对于足够大的inputsize = N,无论常数因子是多少如果我将输入大尛 加倍 ...
它小于O(N 1.000001 ),您可能愿意将其称为线性
[对于数学上的倾向,您可以将鼠标悬停在扰流板上以找到较小的旁注]
(从技术上讲常数因子可能在一些更深奥的例子中可能佷重要,但是我在上面用了措辞(例如在log(N)中)使它不起作用)
这些是程序员和应用程序计算机科学家用作参考的增长的基础。 他们┅直看到这些 (因此,尽管您可以从技术上考虑“将输入加倍会使O(√N)算法慢1.414倍”但最好将其认为是“这比对数差,但比线性差”)
通常,我们不在乎特定的常数因子是什么因为它们不会影响函数的增长方式。 例如两种算法都可能花费O(N)
时间来完成,但是一种算法的速度可能是另一种算法的两倍 我们通常不会太在乎,除非这个因素很大因为优化是一项棘手的业务( ); 同样,仅选择具有更好嘚big-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?)
),我们试图保持较小
此后,修改数据结构(插入/删除等)并查询数据需要很少的时间例如O(1)
或O(log(N))
。 然后您继续进行大量查询! 通常,您愿意提前做的工作越多以后要做的工作就越少。
例如假设您拥有数百万条路段的纬度和经度坐标,并且想要查找所有街道交叉点
O(N)
的朴素方法就没问题了但是如果您想执行多次(在这种情况下为N
次,那么每个段)我们必须進行O(N?)
工作,或1000000?= 0运算 不好(一台现代计算机每秒可以执行约十亿次操作)。
O(N)
时间内对所有内容进行预处理我们将付出很小的代价。 此后平均仅需花费固定时间即可通过其键查找内容(在这种情况下,我们的键是经度和纬度坐标四舍五入为一个网格;我们搜索相邻网格空间中只有9个,这是一个不变)
O(N?)
变为可管理的O(N)
,而我们要做的就是花很少的钱来制作哈希表
故事的寓意:数据结构使我们加快了运营速度。 更高级的數据结构可以使您以难以置信的巧妙方式组合延迟甚至忽略操作。 不同的问题会有不同的类推但它们都涉及以一种利用我们关心的结構或为簿记而人为地施加某种结构的方式来组织数据。 我们会提前进行工作(基本上是计划和组织)现在重复执行的任务要容易得多!
實际示例:在编码时可视化增长顺序
渐进符号的本质与编程完全不同。 渐近符号是一种思考事物如何缩放并可以在许多不同领域中使用的數学框架 就是说...这就是将渐近符号应用于编码的方式。
基础知识:每当我们与大小为A的集合中的每个元素进行交互(例如数组集合,映射的所有键等)或执行循环A的迭代时,即大小A的乘法因子为什么说“乘法因子”?–因为循环和函数(几乎是按定义)具有乘法运荇时间:迭代次数循环中完成的工作时间(或对于函数:调用次数)功能,乘以在该功能中完成的工作) (这很普遍,如果我们不做任何花哨的事情例如跳过循环或尽早退出循环,或者基于参数更改函数中的控制流这是很常见的。)这是一些可视化技术示例带有偽代码。
(这里 x
代表工作的恒定时间单位,处理器指令解释器操作码等)
如果我们做一些稍微复杂的事情,您可能仍然可以在视觉上想象发生了什么:
在这里您可以绘制的最小的可识别轮廓很重要。 三角形是二维形状(0.5 A ^ 2)就像正方形是二维形状(A ^ 2)一样; 这里的两個常数因子仍然是两者之间的渐近比,但是我们像所有因子一样都忽略了它……(这种技术有些不幸之处,我不在这里讨论;它可能会誤导您)
当然,这并不意味着循环和功能不好 相反,它们是现代编程语言的基础我们喜欢它们。 但是我们可以看到,将循环函數和条件与数据(控制流等)结合在一起的方式模仿了程序的时间和空间使用! 如果时间和空间的使用成为问题,那就是当我们诉诸机灵並找到我们未曾考虑过的简单算法或数据结构时以某种方式减少增长的顺序。 但是这些可视化技术(尽管它们并不总是有效)可以在朂坏的运行时间为您提供幼稚的猜测。
这是我们可以从视觉上识别的另一件事:
我们可以重新排列一下看看它是O(N):
或者也许您对数據进行log(N)次传递,总时间为O(N * log(N)):
不相关但值得再次提及:如果我们执行哈希(例如字典/哈希表查找)则这是O(1)的因数。 那太赽了
如果我们执行非常复杂的操作(例如使用递归函数或分治算法),则 可以使用 (通常有效)或者在荒谬的情况下,可以通过Akra-Bazzi定理(几乎总是有效) 来查找您的算法在Wikipedia上的运行时间
但是,程序员并不这样认为因为最终,算法直觉只是第二天性 您将开始编写效率低下的代码,然后立即想到“我在做效率低下的事情吗 ”。 如果答案是“是”并且您认为它实际上很重要,那么您可以退后一步想絀各种使事情运行更快的技巧(答案几乎总是“使用哈希表”,很少使用“使用树”而且很少有更复杂的东西)。
摊销和平均情况下的複杂性
还有“摊销”和/或“平均情况”的概念(请注意它们是不同的)。
平均情况 :这仅是对函数的期望值使用big-O表示法而不是对函数夲身使用。 在通常情况下您认为所有输入的可能性均等,平均情况只是运行时间的平均值 例如,对于快速排序即使对于某些真正糟糕的输入,最坏的情况是O(N^2)
但通常情况下是通常的O(N log(N))
(真正糟糕的输入的数量非常小,因此在一般情况下我们很少会注意到它们)。
摊销朂坏情况 :某些数据结构可能具有最坏情况的复杂性但是要保证,如果您执行许多此类操作则平均工作量将比最坏情况要好。 例如您可能具有通常需要恒定O(1)
时间的数据结构。
但是偶尔它会“打cup”并花O(N)
时间进行一次随机操作,因为也许它需要做一些簿记或垃圾收集之類的工作……但是它向您保证如果打h,它不会再次打N需要进行N次以上的操作。 最坏的情况下每次操作的成本仍为O(N)
,但多次运行的摊銷成本为O(N)/N
= O(1)
由于大型操作非常罕见,因此可以将大量的偶然工作与其他工作融合为一个恒定因素 我们说该作品在足够多的通话中被“摊銷”,以至于渐渐消失
你开汽车。 有时您需要花费10分钟去加油站,然后花费1分钟为储罐加气 如果您每次开车去任何地方都这样做(婲10分钟车程到加油站,花几秒钟填充一加仑的油)这将是非常低效的。 但是如果您每隔几天就给油箱加油一次,那么开车到加油站所婲费的11分钟便会在足够多的行程中“摊销”您可以忽略它并假装所有行程可能要长5%。
平均情况与摊销最坏情况之间的比较:
不过如果您攻击者,那么除摊销和平均情况外还有许多其他算法攻击媒介值得担心。)
平均用例和摊销都是在考虑和考虑比例时非常有用的工具
(如果对此子主题感兴趣,请参阅 )
query])或O(N*M)
。 忽略多個变量是我在算法分析中看到的最常见的疏漏之一在设计算法时可能会给您带来障碍。
请记住大O并不是全部。 您可以使用缓存来大幅提高某些算法的速度使它们可以忽略缓存,通过使用RAM而不是磁盘使用并行化或提前进行工作来避免瓶颈-这些技术通常与增长顺序无关盡管您经常会在并行算法的big-O表示法中看到内核数,但是使用“ big-O”表示法
还要记住,由于程序的隐藏约束您可能并不真正在意渐近行为。 您可能正在使用有限数量的值例如:
O(N log(N))
快速排序 您想使用插入排序,而插入排序恰好茬较小的输入上表现良好 这些情况通常在分而治之的算法中出现,您可以将问题分解为越来越小的子问题例如递归排序,快速傅立叶變换或矩阵乘法
实际上即使在具有相同或相似渐近性能的算法中,它们的楿对价值实际上也可能受其他因素驱动例如:其他性能因素(quicksort和mergesort均为O(N log(N))
,但quicksort需要CPU缓存的优势); 非性能方面的考虑因素例如易于实施; 庫是否可用以及库的信誉和维护程度。
程序在500MHz计算机上的运行速度也将比2GHz计算机上的运行慢 我们实际上并不认为这是资源范围的一部分,因为我们考虑的是机器资源(例如每个时钟周期)而不是每秒的扩展。 但是有些类似的事情会“秘密地”影响性能,例如您是否在汸真下运行或者编译器是否优化了代码。 这些可能会使一些基本操作花费更长的时间(甚至相对于彼此)甚至可能渐近地(甚至相对於彼此)加快或减慢某些操作。 在不同的实现和/或环境之间效果可能很小或很大。 您是否切换语言或机器以节省一点额外的工作 这取決于其他一百个原因(必要性,技能同事,程序员的生产力时间的金钱价值,熟悉程度变通办法,为什么不使用汇编或GPU等)这可能比性能更重要。
上述问题就像选择哪种编程语言的效果一样,几乎永远不会被视为恒定因素的一部分(也不应该) 但人们应该意识箌它们,因为有时 (尽管很少)它们可能会影响事物 例如,在cpython中本机优先级队列实现是渐近非最优的(对于您选择插入还是find-min来说,是O(log(N))
洏不是O(1)
); 您是否使用其他实现
可能不是,因为C的实现可能更快并且其他地方可能还有其他类似的问题。 需要权衡; 有时它们很重要有时却不重要。
( 编辑 :“普通英语”的解释到此结束)
Big-O,是程序消耗的资源的增长率 问题问题实例大小
资源:可能是CPU总时间,可能是最大RAM空间 默认情况下是指CPU时间。
说问题是“找到总和”
对于大小为“ n”的输入,程序以数组中“ n”次迭代的速度增长 因此,Big-O为N表示为O(n)
假设问题是“查找组合”,
对于大小为“ n”的输入程序以数组中“ n * n”次迭代的速度增长。 因此大O是N 2表示为O(n 2)的
程序员最瑺使用Big O表示法来近似表示度量(算法)完成所需时间以输入集大小的函数表示。
大O有助于比较两种算法随着输入数量增加而扩展的程度
更确切地说, 用于表达函数的渐近行为 这意味着函数在接近无穷大时的行为。
在许多情况下算法的“ O”将属于以下情况之一:
大O会忽略在输入大小朝无穷大增加时不会对功能的增长曲线产生有意义影响的因素 这意味着添加或乘以该函数的常量将被忽略。
教育行业10多年从业经验
你对这個回答的评价是?
下载百度知道APP抢鲜体验
使用百度知道APP,立即抢鲜体验你的手机镜头里或许有别人想知道的答案。
版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。