算法是使高效的程序成为可能的方法。它们解释了如何排列记录、搜索项、计算数值(比如质因子分解)、查找一个街道网络中的最短路径、确定可能通过通信网络的最大流。算法好坏的差别可能意味着是在一秒、一个小时内解决问题,还是永远也不能解决问题。
学习算法使你能建立有用的方法工具来解决具体的问题。它能帮助你理解在不同的情况下,哪个算法是最有效的,所以对于一个特定的问题,你就能选择最适合的算法。对某些数据而言性能优异的算法可能对其他的数据而言表现糟糕。所以知道如何选择一个最适合当前情况的算法是很重要的。
更重要的是,通过学习算法,你可以学习常规的问题解决技巧。即使你已知的任何算法都不能很好地适合当前的状况,你也可以把这些技巧应用到其他问题上。这些技巧让你从不同的角度看问题,使你能创造和分析自己的算法,从而解决你的问题,并且满足没有预料到的需求。
除了帮助你解决工作上的问题,这些技巧甚至会帮助你获得需要使用这些技巧的工作。许多大的科技公司,比如微软、谷歌、雅虎、IBM等公司都想要让他们的程序员理解算法和相关问题的解决技巧。其中,有些公司因为让面试者在面试中解决算法编程和逻辑难题而“臭名昭著”。
好的面试官不一定期待你解决每一个难题。事实上,当你没有解决某个难题时,他们可能会了解更多。最好的面试官想看到你如何处理一个不熟悉的问题,而不是想要看到答案。他们想看到你是举起双手说这个问题在面试中是不合理的,还是你分析了这个问题,并提出了一条有希望的推理来用算法解决这个问题。“天哪,我不知道。或许我要上网搜一下”将会是一个坏的答案。“看起来一个递归的分治法可能有用”将会是一个好得多的答案。
这是一本易读的计算机算法导论书。它描述了一些重要的传统算法,并且说明了每一个算法在什么时候是适合的。它解释了如何分析算法从而理解它们的行为。最重要的,它教会了你创造自己新算法的技巧。
这里是本书中描述的一些有用的算法:
数值算法,比如随机化、分解因式、处理质数、数值积分
熟练操作常见数据结构的方法,比如堆、树、平衡树、B树
排序和搜索
网络算法,比如最短路径、生成树、拓扑排序和流计算
这里是本书中解释的一些常规的问题解决技巧:
暴力或者穷举搜索
分治法
回溯法
递归
分支界限
贪心算法和爬山法
最小花费算法
缩小范围
. 启发式算法
为了帮助读者掌握这些算法,本书提供了一些练习,读者可以利用它们来探索自己的方法,以便修改书中的算法并把它们应用到新的情况中。这些练习也会帮助你巩固算法中的主要技巧。
最后,本书包含了解决面试中可能遇到的算法问题的技巧。算法技巧会让你解决许多面试中的难题。即使你不能用算法技巧解决每一个难题,至少表明你熟悉这些方法并且能用它们解决其他的问题。
算法选择
本书中的每一个算法都是因为一个或多个下列原因而被选择的:
这个算法是有用的,并且有经验的程序员应该能理解它如何工作以及如何在程序中使用它。
这个算法展示了你可以应用到其他问题中的重要算法编程技巧。
计算机科学专业的学生普遍学习这个算法,所以这个算法或者它使用的技巧可能出现在一个技术性面试中。
当读者读完本书并做完练习后,将会有一个好的算法基础并掌握解决自己编程问题的技巧。
本书的目标人群
本书主要针对三种读者:专业程序员、准备面试的程序员和学习编程的学生。
专业程序员将会发现本书中所描述的算法和技巧对于解决他们工作中遇到的难题是很有用的。即使遇到无法直接用书中的算法解决的问题,阅读本书中的算法也会让你从新的角度观察问题,从而发现新的解决办法。
准备工作面试的程序员可以使用本书来磨炼他们的算法技巧。你的面试可能不会包括书中描述的任何问题,但是可能包含一些足够相似的问题。你可以用从本书中学到的技巧解决它们。
学习编程的学生应该学习这些算法。本书中描述的许多方法是简单、富有魅力而且有效的。但是它们并不都是十分显而易见的,所以你不一定会在偶然间自己发现它们。递归、分治、分支界限等技巧,还有使用众所周知的数据结构,这些对任何有兴趣编程的人都是十分需要掌握的。
注就我个人而言,算法只是一种乐趣,它们就像填字游戏或者数独一样。我喜欢组成一个复杂的算法,倒一些数据进去,然后看到一个美丽的三维图形、一条匹配一系列点的曲线,或者一些其他的优雅的答案出现。我喜欢这种感觉。
充分运用本书
仅仅是阅读本书,就能学到一些新的算法和技巧。但是要真正掌握这些算法体现出的方法,就需要用它们工作,需要用某种编程语言实现它们。你还需要实验、修改这些算法,尝试旧问题的新变型。本书中的练习和面试问题能让你想到使用这些算法中技巧的新方法。
为了从本书中得到最大的收获,我强烈推荐用一种你最喜欢的语言实现尽可能多的算法。甚至用多种语言来实现,看看不同的语言是如何影响问题实现的。你应该研究这些练习并至少写下解决它们的提纲。理想状况下,你也应该实现它们。通常一个练习被编入本书是有原因的,你可能需要认真审视这个问题,才能发现这个原因。
最后,看看网上的一些面试问题,然后弄明白你将如何解决它们。在许多面试中,可能不会要求你实现一个解决方案,但是你应该能勾勒出大体的解决方案。如果你有时间实现解决方案,你将会学到更多。
理解算法是一个实践问题。不要害怕放下书,打开一个编译器,写一些真正的代码吧。
本书的网站
其实,本书有两个网站:Wiley的版本和我的版本。每一个网站都包含了本书的源代码。
Wiley的网址是http://www.wiley.com/go/essentialalgorithms。你也可以去http://www.wiley.com通过书名或ISBN来搜索这本书。一旦找到了这本书,可以点击“下载”(Downloads)标签来获取本书的所有源代码。一旦下载了这些代码,只需要用你喜欢的压缩工具解压它们即可。
注在Wiley的网站,你可能会发现用ISBN搜索更容易。本书的ISBN是978-1-118-61210-1。
要想在我的网站上找到这本书,请登录http://www.CSharpHelper.com/algorithms.html。
本书的结构
这一部分介绍了本书的详细内容。
第1章解释了分析算法中必须理解的概念。其中讨论了算法与数据结构之间的不同,引入了大O符号,并介绍了当实际因素比理论运行时间计算更重要时的时间问题。
第2章解释了几个处理数值的算法。这些算法用于随机化数字和数组,计算最大公约数和最小公倍数,快速求幂,判断一个数字是否为质数。一些算法还引入了自适应求积和蒙特卡罗模拟这些重要的技巧。
第3章解释了链表数据结构。这种灵活的结构可以用来存储随时间增长的列表。这些基础概念对于建立其他的链接数据结构,比如树和网络,也是很重要的。
第4章解释了特殊的数组算法和数据结构,比如节省程序时间和存储空间的三角形数组和稀疏数组。
第5章解释了让一个程序以先进先出(FIFO)和后进先出(LIFO)的顺序存储和取出元素的算法及数据结构。这些数据结构对于其他算法很有用。它们也可以用来模拟现实世界中的场景,比如在商店中排队结账。
第6章解释了排序算法。这些算法展示了有用的算法技巧。不同的排序算法适应于不同种类的数据,并且有不同的理论运行时间,所以理解这些算法的特点是很有好处的。这些也是为数不多理论性能界限已知的算法,所以研究它们特别有趣。
第7章解释了程序可以用来搜索有序列表的方法。这些算法展示了重要的技巧,比如说二分法和插值法。
第8章解释了散列表—使用额外的存储空间来使一个程序快速查找特定元素的数据结构。它们有力地展示了时间与空间的权衡在许多程序中的重要性。
第9章解释了递归算法—调用其自身的算法。递归技巧使某些算法更容易理解和实现,虽然它们有时会导致问题。所以这一章也介绍了当必要时如何从一个算法中移除递归。
第10章解释了高度递归的树这一数据结构。它对于存储、操作和学习分层数据很有用,并且可以应用在意想不到的地方,比如求算术表达式的值。
第11章解释了在自身随着时间增长时保持平衡的树。一般来说,树结构会变得很高很瘦,并且那将破坏树算法的性能。平衡树通过确保树不变得太高太瘦而解决这个问题。
第12章解释了尝试解决可以被建模为一系列决策的问题的算法。这些算法通常在解决非常困难的问题中使用,所以它们一般只找到近似解而不是可能的最优解。然而,它们是非常灵活的,并且可以被应用到范围很广的问题中。
第13章解释了基础网络算法,比如访问一个网络中的所有结点、检测循环、创建生成树、查找网络中的路径。
第14章解释了更多的网络算法,比如用拓扑排序来安排相关的任务、地图着色、网络克隆、向雇员分配任务。
第15章解释了操作字符串的算法。这些算法中的一部分,比如搜索子串,被内置为工具。大多数编程语言都可以直接使用它们,而不用自己编程。其他的算法,比如括号匹配和查找字符串差异,要求额外做一些工作,而且也展示了一些有用的技巧。
第16章解释了如何加密和解密信息。其中涵盖了加密基础和几个有趣的加密技巧,比如 Vigenère密码、分组密码和公钥加密。这一章没有叙述所有的特定加密算法的细节,比如DES(数据加密标准)和AES(高级加密标准),因为它们更适合在一本加密的专著中介绍。
第17章解释了计算机科学中最重要的两类问题:P(可以在多项式时间内解决的问题)和NP(不能在多项式时间内解决的问题)。这一章介绍了这些类别,证明一个问题属于P还是NP,还有计算机科学中最深刻的问题:P等于NP吗?
第18章解释了在多处理器上运行的算法。几乎所有的现代计算机都包含着多处理器,并且未来的计算机将会包含更多,所以这些算法对于最有效地利用一台计算机的潜在能力至关重要。
第19章介绍了一些窍门和技巧,读者可以用它们来攻克编程面试中可能遇到的难题和挑战。这章还包括一个网站列表,这些网站上有大量读者可以用作练习的难题。
附录A总结了本书中算法使用的观点和策略,使读者可以解决这里的算法没有明确涵盖的其他问题。
附录B包含每章末练习的解答。
使用本书需要的知识
读者不需要任何特殊的知识就能阅读本书和理解书中的算法。然而,如果读者真的想掌握这些知识,应该用某种实际的编程语言尽可能多地实现算法。用任何语言完成算法的具体实现将会帮助读者更好地理解算法的细节和语言要求的特殊处理方法。
当然,如果读者打算使用一种编程语言实现算法,需要配备合适的开发环境。
本书的网站上提供了在Visual Studio 2012中用 C#编写的实现实例,读者可以下载并考查它们。如果想运行那些程序,需要在一台能很好运行Visual Studio的计算机上安装C# 2012。
运行任何版本的Visual Studio,都要求你有一台相当快的、有大的硬盘和内存的现代计算机。例如,我很高兴我的计算机有2GB内存、500GB硬盘、1.83GHz的Intel Core 2系统。硬盘空间比我需要的大许多,但是硬盘相对便宜,为什么不买大的呢?
读者可以在一台功能不是很强大的计算机上运行Visual Studio,但是使用功能不强的计算机会非常缓慢且令人沮丧。Visual Studio会占用很大的内存,所以,如果计算机遇到了性能问题,安装更多的内存可能会有帮助。
这些程序将会用C# Express Edition 载入和执行,所以没有必要安装更贵的C#版本。你可以在http://www.microsoft.com/visualstudio/eng/downloads#d-express-windows-desktop上获得C# Express Edition的更多信息并下载C#。
约定
为了帮读者充分利用本书,并了解正在发生的事情,我在本书中使用了几个约定。
漂亮的边框
像这样的边框包含着更多的信息和副主题。
注像这样的格式有注释、指导、提示、技巧和当前讨论的旁白。
至于文本中的样式:
新的术语和重要的词语在被引入时表示为楷体。
击键操作,比如Ctrl+A,意味着先按住Ctrl键再按A键。
文本中的URL和电子邮件地址用斜体表示,比如http://www.CSharpHelper.com和 RodStephens@CSharpHelper.com。
给我发电子邮件
如果你有任何疑问、意见或建议,请随时给我发电子邮件至RodStephens@CSharpHelper.com。我不能保证解决你所有的算法问题,但我一定尽力为你指明正确的方向。
致谢
感谢Bob Elliott、Tom Dinse、Gayle Johnson和Daniel Scribner,是他们的努力使本书得以出版。同时感谢技术编辑George Kocur、Dave Colman和Jack Jianxiu Hao,他们的帮助确保了本书中的信息尽可能准确。