学习用于同一目的的不同算法/数据结构的原因是什么?


91

自从我是一名本科生以来,我一直在想这个问题。这是一个普遍的问题,但我将在下面详细说明。

我见过很多算法-例如,对于最大流量问题,我知道大约3种算法可以解决该问题:福特-富克森(Ford-Fulkerson),埃德蒙兹-卡普(Edmonds-Karp)和狄尼克斯(Dinic),其中狄尼克斯具有最高的复杂性。

对于数据结构(例如堆),有二进制堆,二项式堆和Fibonacci堆,其中Fibonacci堆具有最佳的整体复杂性。

让我感到困惑的是:我们有什么理由需要全部了解它们吗?为什么不学习并熟悉最好的复杂性呢?

我知道这是最好的,如果我们都了解它们,我只是想知道是否有任何“更有效的”原因,例如某些问题/算法只能通过使用A而不是B来解决,等等。


17
我经常说:这些(通常)不是“最好的”。一旦明确定义了“更好”的含义,答案就显而易见了。
拉斐尔

2
这是一个很好的问题,但它说明了我认为您可能需要进行纠正的教育漏洞。那是实践经验,如果您在学习期间尚未实际编写这些算法,则可以考虑现在编写它们,我怀疑在您尝试找到它们的用途时,对这个问题的答案会很快变得显而易见。
山姆

@Sam根据我的经验,我认为在讲座或某些教科书中,它们是有启发性的,介绍了许多算法,分析等,但是并没有很多实际案例或示例场景能够使A胜过B。它们可能涵盖了算法A到Z的类型以及一些家庭作业问题,但对我来说,它们只能由A或仅由Z等解决,因此提出了问题。
shole

5
如果您坚持将学术兴趣放在一边,那么最好的实践理由就是要学习少于最佳算法,这是您可以识别它们的本质,并通过重构为最佳算法来对其进行优化。如果您不知道弓箭的用途,则无法将弓箭升级为枪支。
candied_orange '16

1
实际上,我们已经提出了一个StackExchange网站来专门帮助解决诸如此类的CS教育问题。来支持我们在这里:area51.stackexchange.com/proposals/92460/...
vk2015

Answers:


121

有一本书等待出版,标题为《数据结构,算法和权衡》。您可能会在本科阶段学习的几乎每种算法或数据结构都具有某些功能,这使其在某些应用程序中比其他应用程序更好。

让我们以排序为例,因为每个人都熟悉标准的排序算法。

首先,复杂性不是唯一的问题。在实践中,常量因素很重要,这就是为什么(例如)快速排序比堆排序更多地被使用的原因,即使快速排序具有最糟糕的最坏情况复杂性。

Øñ日志ñ

在其他情况下,来自算法或数据结构的想法可能适用于特殊目的的问题。冒泡排序似乎总是比实际硬件上的插入排序慢,但是执行冒泡传递的想法有时正是您所需要的。

例如,考虑一下现代视频卡上的某种3D可视化或视频游戏,出于性能原因,您希望在其中按从最接近相机到最远离相机的顺序绘制对象,但是如果您无法获得准确的订单,则硬件将负责处理。如果在3D环境中移动,则对象之间的相对顺序在帧之间不会有太大变化,因此,每帧执行一次气泡传递可能是一个合理的权衡。(Valve的Source引擎这样做是为了产生粒子效果。)

持久性,并发性,缓存局部性,在群集/云上的可伸缩性,以及许多其他可能的原因,即使您关心的操作具有相同的计算复杂性,一个数据结构或算法可能比另一个更合适。

话虽如此,这并不意味着您应该记住一堆算法和数据结构,以防万一。大部分战斗是在意识到首先要权衡要利用的东西,并且如果您认为可能存在适当的东西,则知道要去哪里寻找。


7
很好的例子,很好的答案!甚至不知道泡泡通行证在现实世界中有实际用途...
shole

1
@shole我在游戏行业没有很多经验,但是以上所有这些在不同程度上都很重要。(显然,游戏所需的算法,数据结构和数学类型可能与数据库或生物信息学或您所拥有的算法不同。)如果我是您,我会去这里开始观看:纯手工制作的英雄。 org 也可能值得在gamedev.stackexchange.com上
别名

1
缓存效率是一个尚未得到充分研究的重要因素(谷歌“内存墙”)。
拉斐尔

6
小心一点,Quicksort的平均速度要比Heapsort快得多,但是Heapsort的一致性更高(运行时间的差异较小,最坏的情况要好得多)。一旦缓存/分页开始发挥作用,Heapsort在阵列中的跳跃与Quicksort从左右方向进行的线性扫描就大为不同。
vonbrand

1
@shole您对哪种游戏开发感兴趣?至少有两个非常不同的子字段,即3D图形和游戏玩法(包括AI)。我只有图形方面的经验,但是我可以说数据结构和数学在图形中非常重要,而算法在较小程度上也是如此。如果您使用的是引擎,那么这些东西中的大多数当然都会得到解决,但是您仍然应该了解3D几何的基本数学原理。
gardenhead '16

51

除了在无数的机器模型(TM,RAM,PRAM等)上存在无数的成本衡量指标(运行时间,内存使用,高速缓存未命中,分支错误预测,实现复杂性,验证的可行性...)这一事实之外, ,平均与最差情况以及摊销等因素相互权衡,通常在基本教科书规范范围之外还存在功能差异

一些例子:

  • Mergesort是稳定的,而Quicksort不是。
  • 二进制搜索树为您提供有序的迭代,而哈希表则没有。
  • Bellman-Ford可以处理负边权重,Dijkstra不能。

还有一些教学上的考虑因素

  • 在较简单的解决方案之前了解一个涉及更多的解决方案有多容易?(没有BST的AVL树(及其分析);没有Ford-Fulkerson的Dinic; ...)
  • 与每个问题只接触一个解决方案相比,您遇到的原理和模式是否相同?
  • 暴露于每个问题一个解决方案是否可以提供足够的培训(掌握)?
  • 您是否应该知道找到了哪些解决方案的广度(以防止您一遍又一遍地重新发明轮子?)?
  • 如果每个问题仅遇到一个解决方案,您是否会理解在野外找到的其他解决方案(例如,在现实世界的编程库中)?

  1. 对于没有可用的丰富CS工具箱的程序员类型,我们可以从中看到很多东西。

4
+1,包括教学论依据!与几种基本原理(尤其是第二和第三种原理)相关,了解如何开发和优化算法和数据结构可以教授开发和优化技术以及对折衷的理解(不仅要学习“什么”,还要学习“如何”和“为什么”) )。
保罗·克莱顿

2
进一步的考虑是,分析不同的替代方案提供了有用的工具示例,可用于分析可能用于异常设置的新算法。
vonbrand '16

1
好点,@ vonbrand。发明了摊销的复杂度分析来了解八叉树的行为,但是八叉树在实践中很少使用。好吧,无论如何,不​​要像以前那样散布树木。Windows NT内核著名地使用展开树来实现虚拟内存映射,但是它不会在每次查找时都重新排序。
别名

1
@vonbrand是的。我会理解,尽管有人对此算法类最感兴趣的工具箱维度会因此而sc之以鼻。
拉斐尔

7

现实世界中,有时您可能正在使用由其他人编写的软件。其中一些软件是在您出生之前编写的!

为了了解所使用的算法/数据结构,了解大量算法/数据结构(包括不再被视为“最新技术”的选项)非常有帮助。

您还必须处理非标准的算法,这些算法仅在您正在处理的应用程序中使用。当您必须研究这些人如何改进算法时,当您必须改进这些算法时,您会发现大脑已经充满了有用的方法来改进算法。

这使那些学习计算机科学的人与刚刚学会编程的人脱颖而出。在我从事的大多数工作中,有一段时间学习计算机科学可以解决一个“从书本上学习”的程序员无法解决的问题,但是95%的时间我发现学习计算机科学没有给我带来任何好处超过其他有经验的程序员


除非您要解决的问题中有95%与机器学习有关。我看不到普通程序员甚至如何有机会尝试真正的ML问题所面临的任何问题。
Pinocchio

3
目标:找到一份工作率高于5%的工作。
拉斐尔

请记住,学习CS是收集有关算法和数据结构知识的好方法。编码最好的职业-对于编码人员。
灰胡子

5

许多人正确地提到,通常没有一种最佳算法-这取决于情况。

还有一天,您可能会遇到一种陌生的情况。您知道的算法越多,您就会有更多的机会知道几乎可以用作基础解决方案的算法。


5
该答案仅重复较旧的观点。
拉斐尔

1

尽管拉斐尔(Raphael)的回答在某种程度上提到了这一点,但许多很好的答案,只是我认为缺少的东西。

易于实施也是要考虑的问题。
对于排序算法,这通常不是问题,因为大多数平台/语言已经实现了一种(通常比您能做的更好),但是可能无法使用更多不寻常的算法。
根据您的问题,如果实施时间是1天2周,则可能不需要绝对最佳的算法。

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.