我正在学习计算复杂性的课程,到目前为止已经给人的印象是它对开发人员没什么帮助。
我可能错了,但如果你之前走过这条道路,请你举一个例子说明复杂性理论如何帮助你完成工作?非常感谢。
答案 0 :(得分:51)
O(1):没有循环的普通代码。刚流过。查找表中的查找也是O(1)。
O(log(n)):有效优化的算法。示例:二叉树算法和二进制搜索。通常不会受伤。如果你有这样的算法,你很幸运。
O(n):数据上的单个循环。非常大的伤害。
O(n * log(n)):一种执行某种分而治之策略的算法。伤害大n。典型示例:合并排序
O(n * n):某种嵌套循环。即使是小n也会受伤。与天真矩阵计算相同。如果可以的话,你想避免使用这种算法。
O(对于x> 2,n ^ x):具有多个嵌套循环的邪恶构造。伤害很小的n。
O(x ^ n,n!和更糟):你不希望在生产代码中使用的怪异(通常是递归)算法,除非在非常受控的情况下,对于非常小的n,如果真的没有更好的替代方案。计算时间可能会爆炸,n = n + 1。
从更高复杂度的类中移动算法可以使您的算法飞行。考虑傅立叶变换,其具有O(n * n)算法,除了极少数情况外,该算法在20世纪60年代的硬件中无法使用。然后Cooley和Tukey通过重新使用已计算的值来减少复杂性。这导致FFT广泛应用于信号处理。最后,这也是史蒂夫·乔布斯为iPod赚大钱的原因。
简单的例子:Naive C程序员编写这种循环:
for (int cnt=0; cnt < strlen(s) ; cnt++) {
/* some code */
}
由于strlen()的实现,这是一个O(n * n)算法。嵌套循环导致big-O内部复杂性的增加。 O(n)内的O(n)给出O(n * n)。 O(n)内的O(n ^ 3)给出O(n ^ 4)。在该示例中,预先计算字符串长度将立即将循环转换为O(n)。 Joel has also written about this.
然而,复杂性课程并非一切。你必须留意n的大小。如果由于重新加工(现在线性)指令的数量大量增加,则将O(n * log(n))算法重新编写为O(n)将无济于事。如果n很小,那么优化也不会产生太大的影响。
答案 1 :(得分:10)
虽然确实可以在没有对算法复杂性的任何理解的情况下在软件开发方面取得很大进展。我发现我一直都在使用复杂的知识;但是,在这一点上,它往往没有意识到它。学习复杂性的两件事让你作为一个软件开发人员可以比较做同样事情的非相似算法(排序算法是典型的例子,但大多数人实际上并没有编写自己的排序)。它给你的更有用的东西是一种快速描述算法的方法。
例如,考虑SQL。 SQL每天都被大量的程序员使用。如果您要查看以下查询,那么如果您研究了复杂性,那么您对查询的理解就会大不相同。
SELECT User.*, COUNT(Order.*) OrderCount FROM User Join Order ON User.UserId = Order.UserId
如果你已经研究过复杂性,那么你会理解是否有人说某个DBMS是O(n ^ 2)。没有复杂性理论,这个人就不得不解释表扫描等问题。如果我们在Order表中添加索引
CREATE INDEX ORDER_USERID ON Order(UserId)
然后上面的查询可能是O(n log n),这会对大型数据库产生巨大的影响,但对于小型数据库来说,它根本就没什么。
有人可能会说复杂性理论不需要理解数据库是如何工作的,而且它们是正确的,但复杂性理论提供了一种思考和讨论处理数据的算法的语言。
答案 2 :(得分:6)
对于大多数类型的编程工作,理论部分和证明本身可能没有用,但他们正在做的是尝试给你直觉,能够立即说“这个算法是O(n ^ 2)所以我们不能在这一百万个数据点上运行它“。即使在对大量数据进行最基本的处理时,您也会遇到这种情况。
快速思考复杂性理论对我来说在商业数据处理,GIS,图形编程和理解算法中一直很重要。这是CS研究中最有用的课程之一,与你通常自学的方法相比。
答案 3 :(得分:4)
计算机不聪明,他们会做任何你指示他们做的事情。编译器可以为您优化代码,但它们无法优化算法。人脑工作方式不同,这就是你需要了解大O的原因。考虑计算斐波那契数。我们都知道F(n)= F(n-1)+ F(n-2),从1,1开始,您可以在线性时间内轻松计算以下数字。但是,如果你告诉计算机使用该公式(递归地)计算它,它将不是线性的(至少在命令式语言中)。不知何故,我们的大脑优化算法,但编译器不能这样做。因此,您必须工作 算法才能使其更好。
然后,您需要接受培训,发现看起来非常明显的大脑优化,查看代码可能无效的时间,了解坏的和良好算法的模式(在计算复杂性方面)等等。基本上,这些课程有几个方面:
答案 4 :(得分:2)
这非常重要。如果您不了解如何估计并计算出算法运行所需的时间,那么您最终会编写一些非常慢的代码。在编写算法时,我一直在考虑计算复杂性。编程时应始终牢记这一点。
在许多情况下尤其如此,因为虽然您的应用程序可以在具有较小测试数据集的台式计算机上正常工作,但了解应用程序在您使用它后的响应速度非常重要,并且有数百种成千上万的人使用它。
答案 5 :(得分:2)
是的,我经常使用Big-O符号,或者更确切地说,我使用它背后的思维过程,而不是符号本身。很大程度上是因为组织中的开发人员很少,我经常理解它。我并不是要对那些人不尊重,但根据我的经验,对这些东西的了解是“男人们对男人进行分类”的事情之一。
我想知道这是否只能获得“是”答案的问题之一?令我感到震惊的是,理解计算复杂性的人群大致相当于认为重要的人群。所以,任何可能回答否的人可能都不理解这个问题,因此会跳到下一个问题,而不是停下来回应。只是一个想法; - )
答案 6 :(得分:1)
有些时候你会遇到需要考虑问题的问题。有许多现实世界的问题需要操纵大量数据......
例如:
学习计算复杂性课程将有助于您分析和选择/创建对此类场景有效的算法。
相信我,从T(3n)下降到T(2n)这样简单的事情可以在以天为单位测量“n”时产生巨大的差异,如果不是几个月的话。
答案 7 :(得分:1)
这里有很多好的建议,我相信大多数程序员偶尔会使用他们的复杂性知识。
但是我应该说理解计算复杂性在游戏领域极为重要!是的,你听说过,“无用”的东西就是游戏编程所依赖的东西。
我敢打赌,很少有专业人士可能会像游戏程序员一样关心Big-O。
答案 8 :(得分:1)
我经常使用复杂度计算,很大程度上是因为我使用非常大的数据集在地理空间域中工作,例如涉及数百万甚至数十亿笛卡尔坐标的过程。一旦你开始遇到多维问题,复杂性就成了一个真正的问题,因为在一个维度上O(n)的贪婪算法突然在三维中跳到O(n ^ 3)并且它不需要太多数据制造严重的瓶颈。正如我在a similar post中提到的,当你开始处理不同大小的复杂对象组时,你也会看到大的O符号变得很麻烦。复杂度的顺序也可以是非常依赖于数据的,典型案例的表现要好于设计良好的ad hoc算法的一般情况。
还需要在分析器下测试您的算法,看看您的设计是否是您所获得的。我发现大多数瓶颈都可以通过算法调整得到更好的解决,而不是提高处理器速度,原因很明显。
有关一般算法及其复杂性的更多阅读,我发现Sedgewicks work既有信息又可访问。对于空间算法,O'Rourkes关于计算几何的书非常出色。
答案 9 :(得分:1)
在您的日常生活中,不要靠近计算机,您应该应用复杂性和并行处理的概念。这将使您更有效率。缓存一致性。那种事。
答案 10 :(得分:0)
一个很好的例子可能是当你的老板告诉你做一些程序时,你可以通过使用计算复杂性理论证明你的老板要求你做的事情是不可能的。
答案 11 :(得分:0)
是的,有一天,当我不得不对一堆学生考试进行排序时,我对排序算法的了解就派上用场了。我使用了合并排序(但不是quicksort或heapsort)。编程时,我只使用库提供的任何排序例程。 (还没有必要对大量数据进行排序。)
我一直在编程中使用复杂性理论,主要是决定使用哪种数据结构,以及何时决定是否或何时对事物进行排序,以及进行许多其他决策。
答案 12 :(得分:0)
'是'和'没有'
是)在开发和实施算法时,我经常使用big O-notation。 例如。当你应该处理10 ^ 3项并且第一个算法的复杂度是O(n log(n))而第二个算法的复杂度是O(n ^ 3)时,你可以说第一个算法几乎是实时的,而第二个算法则需要相当多的计算。
有时对NP complexities classes的了解很有用。它可以帮助您意识到,当一些NP完全问题可以减少到您正在考虑的问题时,您可以不再考虑发明有效的算法。
没有)我上面所描述的只是复杂性理论的一小部分。因此很难说我使用它,我使用它的次要部分。
我应该承认,有许多软件开发项目不会以复杂的方式接触算法开发或使用它们。在这种情况下,复杂性理论是无用的。普通的算法用户经常使用“快速”和“慢速”,“x秒”等词语进行操作。
答案 13 :(得分:0)
@Martin:你能详细说明它背后的思考过程吗?
它可能没那么明确,只需坐下来制定一个解决方案的Big-O表示法,但它会引发对问题的认识 - 并引导您寻找更有效的答案并远离方法中的问题你可能会。例如O(n * n)与更快的东西,例如搜索存储在列表中的单词与存储在trie中的单词(设想示例)我发现它会对我选择使用的数据结构产生影响,以及我将如何处理大量记录。