it-swarm.cn

在行业工作时,big-O真的相关吗?

在我参加的每次采访中,我都对复杂性的数学分析(包括big-O符号)进行了测验。

大O分析与行业发展之间的相关性如何?您真正使用它的频率有多高?对问题有一个磨练的心态有多必要?

66
MM01

我的问题是,该测试与行业发展有何关联?

对计算复杂性理论(例如大O表示法)的扎实理解对于设计可伸缩算法,应用程序和系统至关重要。由于可伸缩性与行业中的计算高度相关,因此大的O符号也是如此。

您多久使用一次它,对问题有一个磨练的心态有多必要?

取决于您“实际使用”的意思。一方面,我从未为所写软件做过计算复杂性的形式证明。另一方面,大多数日子里,我不得不处理可扩展性是潜在问题的应用程序,并且设计决策包括根据其复杂性特征选择(例如)适当的收集类型。

(我不知道是否可能一致地实现可伸缩系统没有对复杂性理论有扎实的理解。我倾向于认为事实并非如此。)

76
Stephen C

这样做的原因是因为它指示可伸缩性

O(n ^ 2)的过程将比O(n log n)的过程更差,但比O(n ^ 3)甚至O(n!)的过程更好。

如果您不知道这些差异以及它们何时适用,则不适合选择正确的功能实现,以及将测试性能推算到生产性能中。


编辑:从 http://www.codinghorror.com/blog/2007/09/everything-is-fast-for-small-n.html (反过来又来自Programming Pearls)

enter image description here

36
user1249

这取决于你在做什么。

对于Web开发人员(例如我),这通常很重要。您要扩展Web应用程序。如果您的应用程序有一个可以扩展为O(n ^ 2)的瓶颈,并且您认为这很好,因为您的服务器可以同时处理1000个用户,那么您似乎无需理会。事实是,要处理两倍(相当可能在夜间发生),您将需要四倍的计算能力。理想情况下,您希望Web应用程序按O(n)进行扩展,因为硬件在合理的恒定用户/服务器比率下很便宜。

通常在应用程序中,如果您有10万个对象,大O就会吃掉您。您极易受到高峰攻击。例如,我目前正在开发3D游戏,这是一个处理数据负载的应用程序。除了渲染之外,您还可以进行碰撞检查,导航等操作。您需要高效的算法,需要大量的缓存,因此效率较低的算法会摊销。等等。

当然,如果您要做的是像通过在界面设计器中组合一个GUI来制作移动应用程序,然后将其与某些Web服务结合在一起,那么您永远不会遇到复杂性问题。因为您调用的Web服务已经解决了这一问题。

32
back2dos

在工作生涯中,我从未真正正式应用过规则。

但是,您必须熟悉该概念,并在每次设计算法时以直观的方式应用它。

规则是:

您应该对O表示法足够熟悉,以便能够确定给定任务是否需要对其进行正式计算,或者足以直观地对其进行评估,或者是否可以完全跳过它。就像许多其他基本数学概念一样。

22
Wizard79

好吧,也许有一个小故事可以启发您为什么一定要IS

在我从事的一个项目中,有一个程序负责打印所有类型的文档(标签,选择列表等)。该程序由两部分组成,一个部分从数据库中读取所有必需的数据并将其写入到计算机中。 .ini样式的文件,以及读取这些文件并将其填充到模板中的另一部分。这对于标签和小列表(只有几个字段)效果很好,但是当它必须打印约20页的“大”列表时,它运行了将近10分钟。因为访问这些ini文件会导致O(n²)访问时间,所以n是要打印的字段数。

如果该程序的原始程序员理解O表示法,他们将永远不会那样做。用哈希表代替愚蠢的东西使它变得更快了。

10
user281377

Big-O的性能很重要,但是已经被内部化了。

排序和搜索的Big-O性能无关紧要,因为人们通常使用系统提供的功能,并且这些功能将尽可能地好(假设它们通常需要有用)。有些数据结构对于不同的事物更有效,但通常可以根据一般原则进行选择(通常内置于现代语言中)。有某种意义上的算法可扩展或不可扩展。

结果是形式问题很少在实践中出现,但是实践是建立在相同的原则上的。

8
David Thornley

恕我直言,许多计算机科学程序使许多学生在杂草丛中徘徊。这些程序从未完全传达出计算科学的全部内容。学生进入该行业,努力学习如何应用所学的概念,而对它们与现实世界的关系知之甚少。

我要说的是,计算科学的核心是推理能力。然后,您将学习各种方法和技术来执行此操作,并将它们应用于抽象的问题,这些问题是在许多现实世界中发现的原型原型。诀窍是发现现实世界中的这些原型原语,然后推理诸如正确性,复杂性,时间等事物,您可能会同意,这是您需要担心的真实问题。深入了解各部分的行为方式,通常可以使您深入了解整体的行为方式。而且,相同的通用方法和技术也可以应用于整个过程,只是不具有较小,抽象得很好,定义明确的部分所具有的严格性。但是最后,计算科学使您能够做出关于如何安排计算的合理决策,并真正了解计算在各种条件下的行为。

7
Ziffusion

给自己的备忘录!:

我和许多其他人经常问自己这个问题。

我认为我们问这的真正原因是因为我们变得懒惰了。

这些知识永远不会过时或过时。您可能不会每天直接应用它,但是会下意识地使用它,它将对您的设计决策产生积极影响。有一天它可以为您或其他人节省数小时和数天的编码时间。

随着越来越多的问题被第三方库和工具封装,并且越来越多的开发人员可以使用它们,您将需要了解此知识,以将自己与他人区分开来并帮助解决新问题。

5
Conor

并不是的。基本上,我唯一想过的就是访问数据库。我通常会看一下代码,然后说“正在执行n + 1个查询,您应该将其更改为只执行1个或2个”

因为我的所有数据都是从数据库中读取并显示给用户,所以我尝试将正在使用的数据量减至最少,以至于线性算法与O(n ^ 2)算法之间的差异相当大微不足道。

如果有问题,我们将在稍后进行分析和修复。

5
Greg

您提出了三个问题,我认为简短的答案可以帮助到目前为止给出的更长的论点。

此测试与行业发展有何关联?

取决于行业。

在代码速度或代码空间成为问题的任何地方,它都与所涉及的行业完全相关。通常,您需要知道例程将花费多长时间,或需要多少内存(在线/离线)。

您多久一次使用一次?

取决于行业。

如果性能和扩展与手头工作无关,那么只有在严重的性能不足的情况下才很少。如果您是高度使用的关键系统的工程师,则可能每天都会如此。

对问题有一个磨练的心态有什么必要?

完全必要。

您可能每天都必须使用它,或仅在严峻的情况下使用它;但有时会需要。最好是在设计过程中,在问题到来之前,比拼命地分析扼流系统。

3
Orbling

我会说这很频繁。我们通常不证明某事物具有特定的big-O,但我们已将其内在化,并记住/熟悉big-O保证针对特定的数据结构和算法,我们会针对特定用途选择最快的数据结构和算法。拥有一个包含所有选项的库会很有帮助,例如Java集合库或C++ STL。您可以隐式自然地使用big-O 每天 =当您选择使用_Java.util.HashMap_(O(1)查找)而不是_Java.util.TreeMap_(O(lg n)查找)且肯定选择不对整个序列进行线性搜索时_Java.util.LinkedList_(O(n)查找)用于不需要排序访问权限的内容。

当某人选择了次优的实现并且知道更多的人看到了他们的代码时,纠正它们是我们词汇的一部分,“您的实现需要二次时间,但是通过这样做,我们可以将其减少到n-log-n的时间。这种方式”,就像我们使用英语订购披萨时一样自然而自动。

3
Ken Bloom

您可能不必进行形式分析,但至少要对算法复杂性的顺序有一个全面的了解,以及如何比较两种算法,这对于您要进行非常规的工作并使其顺利进行至关重要。

我已经开发了两个不同的系统,这些系统在早期开发中似乎还不错,但是由于有人使用了O(n ^ 2)算法,所以在生产测试中就把硬件屈服了。在这两种情况下,解决方案都是对O(n)=算法)的微不足道的更改。

3
Bob Murphy

他们可能正在开发用于消费的API的地方。 C++ STL是为数不多的对其算法施加复杂性限制的API之一。但是对于日常工作的程序员/高级程序员/设计师/架构师来说,他们的想法并不多。

1
sashang

除了交流思想外,我还没有发现它那么重要,并且我在性能至关重要的领域(光线跟踪,图像和网格处理,粒子系统,物理引擎等)工作,并且不得不设计出许多专有算法和数据结构在研发工作时。在这些领域中,通常只有少数几个非常高效的数据结构和算法可以产生全新的前沿产品,而昨天的算法却使现有产品过时了,因此人们总是追求使工作效率更高。请注意,我从未发表过有关我设计的算法的论文。它们都是专有的。如果这样做,我将需要数学家的帮助来拟定证明等。

但是在我看来,除非算法的伸缩性很差,否则每次迭代的计算工作量通常比算法的可伸缩性更重要。如果有人提出了一种用于光线跟踪的尖端技术,那么我对计算技术(例如它们如何表示和访问数据)比算法复杂性更感兴趣,因为在这种竞争性和创新性的场景中已经有了合理的可伸缩性。提出无法扩展的算法将无能为力。

当然,如果您要比较二次复杂度和线性运算,那是一个巨大的差异。但是我领域的大多数人都有能力避免在史诗输入上应用二次复杂度算法。因此,可扩展性通常被深深地暗示着,并且更有意义和更有趣的问题变成“您是否使用过GPGPU?SIMD?它是否并行运行?您如何表示数据?您是否为了便于缓存而重新组织了它?访问模式吗?需要多少内存?它可以可靠地处理这种情况吗?您是推迟某些处理还是一次完成所有操作?“

如果前者以更优化的模式(例如,或更适合于多线程和/或SIMD)访问内存,则即使是线性算法也可以胜过线性时间算法。有时,由于这些原因,即使是线性算法也可以胜过对数算法,而对于小输入,线性时间算法自然也胜过对数算法。

因此,对我而言,更重要的是某些人可能称为“微优化”,例如数据表示(内存布局,具有热/冷字段拆分的访问模式等),多线程,SIMD,有时还包括GPGPU。在这个领域,每个人都已经足够有能力在所有时间都发表新论文的情况下,使用体面的,前沿的算法来处理所有问题,在击败算法向导方面,您的竞争优势并不是来自算法复杂性的提高,而是更加直接计算效率。

我的领域是由杰出的数学家主导的,但并非总是知道他们正在做的计算成本的人,或者不是很多加速代码的低级技巧的人。尽管我的复杂性不高,但是在设计更快,更严格的算法和数据结构时,通常这是我的优势。我正在尝试硬件喜欢的东西,朝着比特和字节的方向努力,即使我比真正复杂的算法做更多的工作迭代,也使每次迭代的工作便宜得多-在我的情况下,工作便宜得多。我编写的代码也往往更简单。如果人们认为难以直接理解算法和数据结构的微观优化版本难以理解和维护,请尝试理解和维护一系列行业从未见过的与网格相关的奇特算法和数据结构,并撰写20页的论文以数学方式描述其步骤。

作为一个基本示例,我想出了一个简单的网格结构,该结构最终在我们公司的KD树中胜于碰撞检测和冗余点移除。我愚蠢的原始网格在算法上没有那么复杂,在数学上和算法上都比以他用新颖的方式找到中点的方法实现KD-tree的家伙笨拙,但是我只是调整了网格的内存使用和访问模式,这足以胜过更复杂的东西。

我拥有的另一个Edge(使我能够在比我聪明得多的人所主导的领域中生存)只是真正了解用户的工作方式,因为我使用的软件开发方式相同。这给了我一些算法的想法,这些算法实际上非常符合用户兴趣。作为一个基本示例,大多数人都尝试使用空间索引来加速诸如碰撞检测之类的事情。我在大约几十年前就对有机模型进行过一次简单的职业塑造观察,例如,如果角色将手放在脸上,则空间索引结构将需要拆分节点并进行昂贵的更新(如果角色)然后将手从脸上移开。相反,如果您基于连接性数据而不是顶点位置进行分区,则最终可以得到一个稳定的层次结构,该结构可以非常快速地更新,而无需拆分或重新平衡树(只需要在动画的每一帧中更新边界框)。 ..像这样的事情-如果一个算法没有高深的数学基础的孩子能够理解,只要他们只了解基本概念,就可以提出这些算法,但是由于数学家们对事物的思考方式与用户的方式不太相近,因此他们无法理解这些算法。工作并且对几何的属性考虑太多,而不是对几何的常用方法进行了过多思考。与算法巫师相比,我更多地依靠一般的计算知识和用户端知识来相处得很好。因此,无论如何,我并没有发现专注于算法复杂性那么重要。

1
user204677

我从数学的角度从未考虑过大O,除非有要求,否则我根本不会考虑大O。我只是在脑海中看到一个算法,我可以判断出它是否不好,因为它对每个N都在内存中进行了多次循环,或者是否确实完成了分而治之。如果需要,我可以在几秒钟内将其转换为大的O表示法,但是对我而言,仅了解算法/容器如何与内存一起工作比思考数学观点要容易得多。

0
Coder

是的,复杂性在行业中至关重要。如果最终设计出关键路径按N平方缩放的事物(事物数量加倍使系统加载四倍),那么达到缩放瓶颈的速度将比具有N缩放事物的速度快得多。

但是,通常并不能作为某种特定形式的复杂性的适当,正式的证明来完成操作,因此,对操作模式的复杂性有一个很好的直觉是一个好的开始。

0
Vatine