算法导论3rd(译)-算法在计算中的作用

注:该文主要以学习为目的,不用作其他用途。初次翻译经典,水平有限,难免错误,望批评指正,以予持续完善。

===================================================================

1 算法在计算中的作用

什么是算法?为什么算法值得研究?相对计算机中使用的其他技术而言算法的作用是什么?在本章中,我们将回答这些问题。

1.1 算法

通俗的说,算法是任何定义明确的计算过程,它以一个或一组值作为输入并产生一个或一组值作为输出。这样算法就是将输入转换为输出所要执行的计算步骤的序列。

我们可以将算法看作是解决一些有明确定义的计算问题的工具。问题的描述笼统的指定了所需要的输入/输出关系。算法描述了一个特定的计算程序来实现该输入/输出关系。

例如,我们可能需要将一个包含数字的序列按非递减的顺序进行排序。这个问题经常出现在事件中,该问题引进许多标准的设计技术和分析工具提供了丰富的资源。排序问题的正式定义如下:

输入:一个由n个数字组成的序列,记为

输出:一个输入序列的排列(重排序),使得

比如,给一个输入序列〈31,41,59,26,41,58〉,一个排序算法的返回结果为〈26,31,41,41,58,59〉。这样的一个输入序列称作排序问题的一个实例。一般来说,问题的一个实例由计算该问题的一个解所需的输入(满足问题描述中的所有强制性约束)组成。

由于许多程序都使用排序作为一个中间步骤,排序是计算机科学中的一个基本操作。因此,有一大批优秀的排序算法供我们使用。对于一个给定的应用程序,哪一个算法最好取决于(除其他因素外)待排序元素数量,已有序元素的多少,在元素值上的限制,计算机的体系结构,以及使用的存储设备的类型:主存,硬盘,甚至是磁带。

对所有的输入实例,一个算法都能以正确的输出结果结束,那么这个算法是正确的。我们说一个正确的算法解决了给定的计算问题。一个错误的算法可能对一些输入实例不能正常结束,或者以错误的结果结束。与你可能期望的相反,如果我们可以控制错误算法的错误率,这些算法有时候会很有用。在第31章我们研究查找大素数的算法时,我们将看到一个具有可控错误率算法的例子。然而通常情况下,我们只关注正确的算法。

算法可以用普通语言、程序、甚至硬件设计来描述。唯一的要求就是这个描述必须对计算过程进行明确的描述说明。

算法可以解决什么样的问题?

算法发展起来绝不是因为排序这唯一的一个计算问题。(当看到本书的厚度时,你可能存在一些质疑。)算法在实际应用中是普遍存在的,比如下面这些例子:

.人类基因工程已经在标识人类DNA中的全部100,000个基因,确定构成人类DNA序列的三十亿个化学碱基对,在数据库中保存这些信息和开发数据分析工具方面取的重大进步。每一个这些步骤都需要复杂的算法。尽管这些问题的解决方法已经超出了本书范围,解决这些生物问题许多方法都从本书的一些章节中的获得思路,这样就使科学家们有效的利用资源来完成任务。当更多的信息从实验室技术中提取出来时,将会在时间(人和机器)和金钱方面进行节省。

.互联网能够使世界各地的人们快速的访问和检索大量的信息。在巧妙算法的帮助下,互联网上的网站能够管理和处理这些大数据。这里算法使用例子包括查找数据传输的最佳路由(在第24章会介绍解决这类问题的技术),以及使用搜索引擎在网页上快速查找特定的信息(在第11和32章会介绍相关技术)。

.电子商务使得商品和服务以电子的形式进行协商和交换,这取决于个人信息隐私,如信用卡号码、密码和银行对账单。电子商务中使用的核心技术包括公钥加密和数字签名(在第31章讨论),主要基于数值计算算法和数论。

.制造业和其他商业企业常常需要有效的分配稀缺资源。一家石油公司可能希望知道在哪里打井会最大限度地发挥其预期利润。政治候选人可能要决定在哪里花钱买竞选广告,能够最大的提高赢得选举的机会。航空公司可能希望尽可能节省的前提安排人员的航班,并且确保每个航班都被覆盖以及遵守政府有关机组排班的规定。互联网服务提供商可能希望确定在哪里放置附加资源能够更有效的为客户服务。所有这些都是使用线性规划解决问题的例子,我们将在第29章研究线性规划。

尽管有些的这些例子的细节超出了本书的范围,我们确实提供了适用于这些问题和问题域的相关技巧。我们还将说明如何解决许多具体的问题,包括以下内容:

.给定一个道路地图,并在其上标注了每对相邻的交叉点之间的距离,我们想确定从一个交叉点到另一个的最短路径。即使我们禁止重复路径,所有可能的路径数量是很巨大的。我们如何在所有可能的路径中选择哪条最短。这里,我们将道路地图(它本身就是实际的道路模型)建模成图(我们将在第Ⅵ部分和附录B介绍),然后我们可以从这个图中找到从一个顶点到另一个的最短路径。我们将在第24章学习如何有效地解决这个问题。

.给我们两个有序序列,我们希望找到X和Y的最长公共子序列。 X的一个子序列是将 X的一些(也可能是全部或者没有)元素去掉后的序列。例如,〈A,B,C,D,E,F,G〉的一个子序列是〈B,C,E,G〉。 X和Y的最长公共子序列的长度给出了一个对两个序列的相似程度的一种度量。例如,在两个DNA序列的碱基对中,如果他们有很长的公共子序列,那么我们可能考虑他们是相似的。如果X有m个符号, Y有n个符号,那么X和Y分别有个可能的子序列。除非mn非常小,否则选择X和Y所有可能的子序列并且匹配完成得需要相当长的时间。我们将在15章看看如何使用一种称为动态规划的常见技术来更加有效地解决这个问题。

.我们有一组机械设计中的零件,每一个零件可能包含其他零件,为了每个零件出现在它被其他零件使用之前,我们需要将这些零件排列起来。如果设计需要n个零件,这样就有 种可能的顺序,其中 表示阶乘函数。由于阶乘函数甚至比指数函数增长的还要快,我们不能切实的生成每一个可能的顺序,然后确定在那个顺序中,每个零件出现在被其他零件使用之前(除非我们只有很少的几个零件)。该问题是拓扑排序的一个实例,我们将在第22章学习如何有效地解决这个问题。

.给定平面上的n个点,我们希望找到这些点的凸包。凸包即包含这些点的最小凸边形。直观的,我们可以将每个点想象成钉在木板上的一个钉子。凸包就可表示为将所有的钉子包围起来的拉紧的橡皮筋。每一个在橡皮筋拐点上的钉子就是凸包的一个顶点。(一个例子见1029页图33.6。)这些点的 个子集中的任何一个都有可能是凸包的顶点。仅仅知道哪些点是凸包的顶点还不够,我们还需知道这些点出现的顺序。因此,凸包的顶点有很多选择。第33章给了两个发现凸包的很好的方法。

上面这些远没有穷尽(你可能从本书的分量再次进行推测),但是表现出许多有趣算法问题的两个共同特性:

1.他们有很多候选的解决方案,其中绝大多数并没有解决手头的问题。从中寻找一个解决手头问题的或者最好的,是一个相当大的挑战。

2.他们都有实际的应用。在上述的问题中,寻找最短路径就是一个最简单的例子。一个运输公司,如卡车或铁路公司,在通过公路或铁路网寻找最短路径上有财务利益。因为采取更短的路径会带来更低的劳动力和燃料成本。又比如互联网上的路由节点可能需要查找网络中的最短路径来达到将消息快速传递的目的。再如一个从纽约开车到波士顿去的人可能需要在一个合适的网站上查找行驶方向,或者在行驶中时她可能使用GPS。

并不是所有通过算法解决了的问题都有一个容易识别的候选解集。例如,假设我们给出一组表示一个信号的样本,我们要计算这些样本的离散傅立叶变换。离散傅立叶变换把时域转换为频域,生成一组数值的系数,从而使我们能够确定不同频率的采样信号的强度。除了在信号处理上的核心应用外,离散傅立叶变换在数据压缩和计算大型多项式和整数的乘积上面都有应用。对于该问题,第30章提供了一种有效的算法,快速傅立叶变换(通常成为FFT),并且该章通过画一个硬件电路的设计图来计算FFT。

数据结构

本书还包含了几种数据结构。数据结构是为了方便访问和修改而用来存储和组织数据的一种方法。没有一个数据结构是万能的,所以明确它们的优势和不足非常重要。

技术

尽管你可以使用本书作为算法的实用指南,一天你可能遇到一个不可能轻易找到已发布算法的问题(比如本书中的许多练习和问题)。本书将教你算法设计和分析技术,使你可以开发自己的算法,证明它们给出正确的结果,并了解它们的效率。不同的章节讨论算法解决问题的不同方面。有些章节是针对具体问题的,如第9章的寻找中位数和顺序统计,第23章的计算最小生成树,以及第26章的确定网络最大流问题。其他章节涉及的技术,如第4章的分治法,第15章的动态规划,第17章的平摊分析。

难点问题

本书的大部分内容是关于高效算法。我们通常衡量效率的是速度,即一个算法需要多长时间来产生结果。然而也存在一个问题,这些问题没有已知的有效解决方案。在第34章将研究一个这类问题的有趣子集,也就是NP完全问题。

为什么NP完全问题很有意思?首先,尽管目前还未发现一个高效的算法来解决NP完全问题,从来没人证明出这样的一个高效算法是不存在的。换句话说,没人知道NP完全问题的高效算法存在与否。第二,这些NP完全问题有着明显特性,那就是它们之中任何一个存在高效的算法,那么所有这些NP完全问题都存在高效的算法。这种NP完全问题之间的关系使得高效解决方案的缺乏更加诱人。第三,一些NP完全问题跟我们所知道的存在高效算法的问题是相似,但不完全相同。计算机科学家对通过对一个问题陈述的小改动如何能引起最著名算法的效率产生很大的变化很感兴趣。

你应该知道NP完全问题,因为他们中有一些在实际应用中出现的频率非常高。如果你被要求对一个NP完全问题开发有效算法,那你很可能花费大量时间并且无果而终。如果你可以证明该问题是NP完全问题,从而可以花费你的时间去开发一个高效算法的好的解决方案,而不是一个最好的。

作为一个具体的例子,考虑一个有一中心仓库的快递公司。每天,在中心仓库把每辆运货车装满,并将它的货物送到多个地址。在一天结束时,每辆运货车必须回到中心仓库,以便准备次日的运输。为了降低成本,公司想选择一个运送停靠的顺序是得每辆车的经过总距离最小。这个问题就是众所周知的“旅行推销员问题”,并且它是NP完全问题。并没有任何已知的高效算法。但是,在一定假设前提下,我们可以得到一些高效算法使得整体的距离并不比最小情况大很多。第35章会讨论这样的“近似算法”。

并发

多年以来,我们可以指望处理器的时钟速度以一个稳定的比率增长。然而物理方面的限制形成了一个对不断增加的时钟速度的根本性障碍。因为功率密度随时钟速度而超线性的增加,会导致时钟速度在足够高时芯片会存在熔化的危险。为了每秒执行更多的计算,芯片被设计为包含多个“核”而不止一个。我们可以将这些多核计算机想象成多个相继的单芯片计算机;换言之,这是一类“并行计算机”。为了在多核计算机上实现最佳性能,我们需要考虑设计并行算法。第27章介绍了一种“多线程”算法模型,它能利用多核的优势。理论上看来该模型具有相当的优势,并且它是一些成功的计算机程序的基础,其中包括一个国际象棋博弈程序。

1.2 作为一门技术的算法

假设计算机无限快并且计算机存储是免费的。你还有什么理由来研究算法么?即使只是因为你还想证明你的解法会终止并以正确的答案终止,那么回答也是肯定的。

如果计算机无限快,对于解决某问题的任何正确的算法都可以。你可能希望使你的实现满足良好的软件工程实践(如,你的实现需要有良好的设计和文档),但是你更通常使用一个最容易的方法去实现。

当然,计算机可能会快,但并不是无限快。存储可能会便宜,但并不是免费的。这样计算时间就是一个有限资源,存储的空间同样如此。你应该精明的使用这些资源,在时间和空间方面高效的算法会提供给你帮助。

效率

解决同一问题的不同算法往往在其效率上有着明显的差异。这些差异会比由硬件和软件引起的更为显著。

例如在第2章中,我们将看到两种排序算法。第一种,称为插入排序,需要大致的时间来对n个元素进行排序,其中是不依赖于n的常数。也就是说,插入排序所需要的时间大致与成比例。第二种,归并排序,需要的时间大致等于,其中表示是不依赖于n的常数。通常插入排序比归并排序具有较小的常数因子,即 < 。我们将看到常数因子对运行时间的影响要远远小于输入规模 。我们把插入排序的运行时间写为,把归并排序的运行时间写成。这样,我们看到插入排序的运行时间里有个的因子,而归并排序有一个更小的因子。(比如,当时,大约是10,当等于一百万时,大约只是20。)尽管对于小的输入规模插入排序通常比归并排序的运行速度要快,然而一旦输入规模足够大时,归并排序的优势,即,将超过常数因子差异的补偿。不论小多少,总存在一个交叉点,在大于该点时归并排序会更快。

作为一个具体的例子,我们让一个较快的计算机(A)来运行插入排序,并让一个较慢的计算机(B)来运行归并排序。两个计算机都对一个1000万数字的数组进行排序。(虽然1000万数字可能看起来很多,若这些数字是8字节的整数,那么这个输入大约占80兆字节,这会占用许多倍的内存甚至是廉价的笔记本电脑。)假设A计算机每秒钟执行一百亿指令(这比编写本书时的任何时序计算机都要快),B计算机每秒钟只执行一千万指令,这样在原生计算能力上A计算机是B计算机的1000倍。为了使差异更为显著,假设世界上最聪明的程序员为A计算机使用机器语言来写插入排序,结果是需要条指令来对个数字排序。再假设,只是一个普通的程序员使用一个低效的编译器和一个高级语言来实现归并排序,结果是需要条指令。为了对1000万数字排序,A计算机需要:


B计算机需要:


通过使用一个运行时间增长的较慢的算法,尽管使用差的编译器,B计算机的执行要比A计算机快17倍多。当我们对一亿个数字进行排序时,归并排序的优势更加明显:其中插入排序需要超过23天,而归并排序需要不到4个小时。一般来说,随着问题规模的增加,归并排序的优势更明显。

算法和其他技术

上述例子表明我们应该像计算机硬件一样把算法作为一项技术。系统的整体性能对于选择高效算法的依赖性与选择快速的硬件一样。正如其他计算机技术做出的快速发展一样,算法也正式如此。

你可能想知道在现代计算机的其他先进技术中算法是否真正重要,比如:

.先进的计算机体系结构和制造技术,

.易用、直观的图形用户界面,

.面向对象系统,

.Web集成技术以及

.快速网络,包括有线和无线。

答案是肯定的。虽然有些应用程序在应用层不明确的需要算法内容(如一些简单的基于Web的应用程序)。例如,考虑一个需要确定如何从一个地方旅行到另一个地方的基于Web的服务。它的实现依靠快速的硬件、图形用户界面、广域网,并且还可能有面向对象。然而,对于一些操作它同样需要算法,如路由查找(可能使用最短路径算法)、地图渲染和地址插值。

另外,甚至一个在应用层不需要算法内容的应用程序也对算法的依赖非常严重。这个应用程序是否依赖于快速硬件?硬件设计中需要算法。这个应用程序是否依赖于图形用户界面?任何GUI的设计都依赖于算法。这个应用程序是否依赖于网络?在网络中路由严重依赖于算法。这个应用程序是否是用机器语言之外的语言编写?那么它是否编译器、解释器或汇编进行处理,所有这些都广泛使用了算法。算法是现代计算机中使用的大多数技术的核心。

此外,随着计算机能力的日益增加,我们使用他们来解决比以往更大的问题。正如我们上面看到的对插入排序和归并排序的对比,算法效率的差异在较大的问题规模是变得尤为突出。

掌握了坚实的算法知识是区分真正熟练的程序和新手的一个特征。使用现代计算技术,你可能在完成一些任务时不需要知道很大有关的算法,但是一个良好的算法背景,你可以做很多、很多。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值