商业周刊/中文版:编程专刊(商业周刊/中文版)
上QQ阅读APP看书,第一时间看更新

什么是算法?

● 一门编程语言就是一个对算法进行编码、命名和组织的系统

● “不要自我重复”,是编程界的口头禅

人们通过使用“算法”(Algorithm)这个词来表示自己对科技很在行。记者喜欢说的“Facebook的算法”或“谷歌的算法”,通常都是不准确的。他们在说的实际是“软件”。

算法不一定要用到电脑,就像几何不一定要用电脑一样。算法是解决问题的,伟大的算法有自己的名字。戴克斯特拉算法得名于著名计算机科学家艾兹赫尔·戴克斯特拉(Edsger Dijkstra),它的作用是在图中确定最短路径。

比如地图;街道和街道在路口相交。这就是一个图!生活中到处是图。水管、电路、代码编译、社交网络、互联网,都可以用图呈现!(现在来想想怎么用这个挣钱……)

许多算法有自己的维基百科页面。你可以花上几天时间四处看看,非常精彩。以欧几里得算法为例,这是所有人在侃算法时必定提到的一个,所以我也从善如流。它是一种计算两个数的最大公约数的简单方法。比如16和12。用后者去除前者。如果有余数(这里有余数4),用余数去除前者,即16,得到4,没有余数,这样就得到了最大公约数——4。(然后把它翻译成机器代码,我们就可以去做别的了)。

有一个网站叫Rosetta Code,用不同语言来演示各种算法。欧几里得算法那个页面非常棒。其中有些例子长得离奇,非常费事,有的则是云山雾罩的微型诗歌,比如这首用Forth语言写的:

: gcd ( a b -- n )
begin dup while tuck mod repeat
drop ;

大声读出来,最好是对着朋友读。(“begin dup while tuck mod repeat drop”,相应的操作为:“开始-复制栈顶元素-循环开始-复制栈顶元素到次栈顶元素之下-循环结束-移去栈顶元素”)Forth是建立在一种叫“堆栈”(stack)的概念上的,这是一种特殊的数据结构。通过定义可进行堆栈操作的“单词”,你就可以渐渐创建一种你自己的语言。激光打印机使用的语言PostScript是在Forth之后出现的,但两者很像。看看两种语言的代码有多相似,也就稍微歪扭了一点:

/gcd {
{
{0 gt} {duprup mod} {pop
exit} ifte
} loop
}.

这就是用PostScript写的欧几里得算法。我承认可能也就我觉得这东西很好玩。下面这段是Python的(所有代码来自Rosetta Code):

defgcd(u, v):
returngcd(v, u % v) if v \
else abs(u)

一门编程语言就是一个以重用(Reuse)和应用为目的,对算法进行编码、命名和组织的系统。这就是为什么说Facebook有算法是很傻的,尽管媒体都这么说。一种算法可以被转译为一个函数,该函数可以在软件执行时被调用。有的算法关系到图像处理,有的是为了提高数据存储效率,有的是为了对一个列表中的要素进行快速检索。多数算法是免费的,已经嵌入到编程语言里,或者辑录成库,放在互联网上供人下载。你可以在完全不考虑算法的情况下进行大量的编程工作——你可以通过代码的剪切、粘贴实现将数据存入数据库,或打印一个网页等操作。但是如果你想让电脑识别出它阅读的是西班牙语还是意大利语,你就需要写一个语言匹配函数。从这个角度讲,算法可以是纯粹的、数学的存在,也可以是想法的实践表达,并非不可亵玩。

有件事我花了很长时间才明白过来:电脑其实并非“数学尖子”。它们可以按照程序,以一定的精确度执行具体的操作,以至于让人类觉得是在“做算术”。戴克斯特拉说:“计算机科学不是关于计算机的科学,就像天文学不是关于望远镜的科学。”计算机科学有相当一部分是在于理解算法的效率——运行起来需要多长时间。电脑很快,但是会被拖慢——比如要在一张巨大的地图上寻找两点之间的最近路径。Google、Facebook、Twitter等公司是建立在基础的计算机科学之上的,非常在意效率,因为它们的用户操作(搜索、状态更新、发推)数量十分惊人。它们完全有必要去寻找优秀的计算机科学家,包括很多博士,这些人知道是什么地方在拖累效率。

计算机科学家需要是一个优秀的数学家,而一个有能力的程序员在数学上只要中等水平就够了。除非他要在一个网络上处理百万级的用户数,或者需要给一百万张照片做快速的模糊或锐化处理,否则他只需要用别人做好的东西就行。遇到真刀真枪的场面,就得用上科学了。当他有某件事需要做一百万亿次时,不起眼的一纳秒延迟会累积起来。系统会变慢,用户会烦躁,钱被整桶整桶地烧掉。

编程最困难的工作是处理那些无法计算的东西,设法把不可能的任务分解成细小的、可行的组件,从而营造出一种电脑在做某事的印象,实际上它并没有在做,比如和人对话。这部分内容原来叫作“人工智能研究”,现在可能更多被归入“机器学习”或“数据挖掘”。当你和Siri或Cortana说话,她们会回应,这并不表示这些服务能理解你;她们只是把你的话转换成文本,把文本分解为符号,然后去和数据库中的词做比对,产生一个回答,其间捆绑和应用了大量的算法,也就是说电脑可以假装听你说话。

这样一来,编程语言就有至少两项基本任务。它需要收纳大量算法以供重用。这样当你需要算平方根时,就不需要临时去找平方根算法。它还要方便程序员添加新的算法和例行程序,以备他们重用。所谓DRY原则,“不要自我重复”(Don't Repeat Yourself),是编程界的口头禅。就是说,命名应该只有一次,事情只做一次,函数只创建一次,让电脑去重复。这个原则并非总能遵守。程序员其实经常要重复自己。有些代码我已经写了好几百遍了。这就为什么说DRY是一个原则。

多说无益。