邹恒明(原来华科大的校友)在美国的密歇根大学读博士的时期出国三本书, 以上是他的第一本《算法之道》(现在已经出了第二版了),我大三的时候将他的三本书都基本上看完了,开篇有一段很犀利的文字,他认为上帝为什么选择第六天 造人呢?因为6=1+2+3,是最小的完全数,而这个世界上已知的完全数不甚了了,而算法,他认为乃是解析这个宇宙的绝对工具。
无何以变为有?
庄 子在《齐物论》里面曰:“一生二,二生三,三生万物”,也就是说,世界上不存在“无”,所有的物质都是由“一”而生。记得在高中的时候,我读过一丁点唯心 主义哲学家黑格尔的《逻辑学》,从无到有的变化为从“无”演变到“自为之有”再在最后演变到“实有”,就是这么一个过程。那么,什么叫做“自为之有”呢? 就是人类的脑细胞的一种形象的思维,但是没有任何的对象,有点像计算机中的数据类型。比如,“100”,是抽象的一个数字,你可以理解为100条 狗,100元钱或者更多的情况,但是,这是一个过程,也就是说,有一种映入人们脑海的一个过程,这个抽象物一旦经过思考,就通过一个过程演化为了实体(从 虚有到实有)。在围棋中,也有所谓“无中生有”的概念,比如,在一个敌人的边亦或是角上做活。
无穷个0相加
还是为0,因为,每一个0都是“确定且静止”的,这里有两层含义,首先是“确定的”,我在“和吴昊一起玩推理”的第一季中解释过0/0的运动性,那么,既 然0是确定的,我们可以将其理解为计算机概念了,但是,可惜的是,算法是有限次的,这是算法的条件之一,但是,我们仍然可以利用算法赋予的思维解释这一问 题,你可以将其分解为无穷个0+0的过程,虽然这个过程无限长,但是,可以预料到结果的确定性。至于静止性,可以对比下文。
无穷个0相乘
同理,还是为0。
无穷个无穷小相加
未定式,这个应该很多人熟知,因为,“无穷”具有某种程度之分,而“无穷小”到底“无穷”到什么程度,也是有区分的,这就很有趣了,和“高阶无穷小”, “低阶无穷小”,“同阶无穷小”和“等价无穷小”的概念类似,“无穷个无穷小相加”可以为0也可以不一定为0,简单的一个例子就是无穷个(这里至少为 n>N)个1/N(N趋于无穷大)相加,由于“两个无穷”会发生激烈的斗争,导致结果是未定的。
无穷个无穷小相乘
这是本文最有趣的地方,我查资料的时候,已经被证明所震撼了,由于无穷小是“运动的”,那么,该运动性最终导致了一个有趣的局面,无穷个无穷小相乘,最终居然被转化为了无穷个1个有界常数列!证明如下:
第1个无穷小是:1,1/2,1/3,1/4,1/5,1/6,……
第2个无穷小是:1, 2,1/3,1/4,1/5,1/6,……
第3个无穷小是:1, 1, 9,1/4,1/5,1/6,……
第4个无穷小是:1, 1, 1, 64,1/5,1/6,……
…………
第k个无穷小是:1, 1, 1, 1,……,k的k-1次方,1/(k+1),……
…………
所有的无穷小的乘积是1,1,1,1,1,1,……
是常数列。
以 上,得证,可以看到,每一个无穷小通过其独特的“运动性”与“不确定性”,被数学奇特地构造出了一个出乎意料的局面(这一点也体现出了数学的严密,一切想 当然的答案都可能会是错误的,我很喜欢看《死亡笔记》中夜神月和Near的对决,哪怕是一丝的可能性,都会造成一个出乎意料的局面!)
静止与运动,确定与不确定
数到底是什么?是一个静止的东西还是运动的?“无穷小”的奇特概念最终造成了奇特的局面,正所谓杨叔子的“人间正道是沧桑”,“沧桑”就指的是变化。
最后,附上邹恒明的文章——《从无有到无穷》
起初神创造天地。地是空虚混沌,渊面黑暗;神的灵运行在水面上。神说:“要有光”。就有了光。神看光是好的,就把光与暗分开了。神称光为昼,暗为夜。有晚上,有早晨,这是头一日。
......
神就照着自己的形象造人,
......
神说:“看哪!我将遍地上一切结种子的菜蔬,和一切树上所结有核的果子,全赐给你们作食物。至于地上的走兽和空中的飞鸟,以及各样爬在地上有生命的物,我将青草赐给它们作食物”。事就这样成了。
神看着一切所造的都甚好。有晚上,有早晨,是第6日。天地万物都造齐了。
图1 米开朗基罗创作的西斯廷教堂穹顶画《创世纪》。这幅画里隐含着算法
6天
圣经上写着:神6天创造天地万有,第7日安歇。
对于神创论者来说,这是不可怀疑的事实。但对于进化论者来说,6天创造一切根本就不可能。
作 为一本算法书,我们当然不打算加入到神创论者和进化论者的永无休止的争论当中去。我们关心的是这么一个问题:圣经上为什么给出的是6天, 而不是其他的时间长度。不管是神创论者还是进化论者,弄清楚6这个数字的来历很可能会对己方的观点有所帮助。在这6天里,神将他的创作方程式重复了6次, 每天1次。对于全能的神来说,他完全可以在1天、1秒或者任何他所愿意的时间长度里创造天地万物,但却为什么是不多不少的6天呢?而不管圣经上的 “1天”是多长,这个问题都是值得讨论的。
我 们知道,任何一个自然数的约数中都有1和它本身,而所有小于它本身的因数叫做这个自然数的真约数。例如,6的所有真约数是1、2、3;8 的真约数是1、2、4。如果一个数的真约数之和等于这个自然数本身,则这个自然数就称为完全数,或者完美数。例如,6 = 1+2+3,因此6是完美数;而8 ( 1+2+4,因此8不是完美数。因此,神6天创造世界,暗示着该创造是完美的!
以 完美数来昭示创造的完美,似乎合情合理。但问题是,完美数只有6这一个数吗?如果不是,为什么不使用其他的完美数呢?答案是,完美数虽然 不止有6这一个,但确实数量稀少。一直到现在(2009年6月),数学家们探索了2600年,并且现代数学家们还借助了超级计算机,但也仅仅找到了47个 完美数。其中第1个完美数是6,接下来的4个完美数分别是: 28、496、8128、33 550 336。而第47个完美数有25 956 377个数位,(注意,是数位,不是数值!)它的数值为:243 112 608 × (243 112 609 ? 1)。
完美数的稀少昭示着达到完美的难度,而神选择6天来创造天地万有也许是因为6是最小的完美数,即创造天地万有对于神来说是轻而易举的一件事情…
完美与算法
完 美数由于其各种神秘属性(真约数之和等于自身只是其中的一个性质)而受到了特殊的关注。但到底哪些数是完美数则不是一件容易判断的事情。 显然,按照完美数的定义,判断一个数是否是完美数的不二法则是找出它的所有真约数,然后求和看看其是否等于自身。然而这种方法效率太过低下,因为这意味着 因式分解,而这是十分困难的(本书后面将会讨论到这个问题)。
如果判断一个数是否是完美数就已经非常困难,那么要找出所有的完美数则更是一个难上加难的任务。因为这就意味着将所有的数进行上面描述的判断验证:因式分解。这似乎是人类不可能完成的任务。即使用世界上超大的计算机来进行计算,情况也不会有任何数量级的改善。
显然,我们需要新的解决方案,而不是发明或使用新的计算工具!研究这样的问题就可以归结到算法的范畴里,因为如何高效地解决问题正是算法要研究的核心课题。
有意思的是,判断和搜索完美数是算法的研究范畴,而算法本身的追求却也是“完美”(见图2)。
图2 算法所追求的理想就是完美
算法无处不在
如果你觉得算法只是用来研究解决找出完美数之类的“漫无边际的问题”,那就大错特错了。
也许算法这个名词听上去很抽象,让人联想不到任何具体的物体。也许你会觉得算法与自己的生活并无太多关系,它只不过存在于那些闲得无聊的数学家或计算机专业人士的脑海中。
但 事实真是这样吗?当然不是。如果我们告诉你算法就是解决各种问题的方法,你就不会觉得它太抽象,与生活无关了吧。事实是,算法无处不在。 每个人每天都在使用不同的算法来活出自己的人生,比如你去食堂买饭会选择一个较短的队列,而有人则可能选择一个推进速度更快的队列。每天起床后,你可能先 读一会儿书,再去吃早饭;另外一个人则可能先去吃早饭,然后读书。所有这些行为都是算法或算法一部分的体现。也许运行这些算法并不在你的思想意识里,也许 你并不知道算法在帮助着自己的生活,但它确实是存在的。这些算法也许没有经过精心设计,没有经过仔细分析,但它还是算法!
2009 年7月23日下午,我在游览云南省大理市的蝴蝶泉时由于泉水边的石头很滑,在用泉水洗手时(导游金花说用该泉水洗手会带来好运)不 慎滑落到蝴蝶泉水(见图3)里面,全身湿透。(据说一天至多只会有一个人滑落到泉里,可见本人运气不错!看来“蝴蝶泉边好梳妆”的歌词也许应该改为“蝴蝶 泉里好冲凉”。)泉水冰冷透凉,而大理的气温又低。这样,我就面临一个是否更换全身衣服的决定。问题是,旅游团需要马上赶去登游船游览洱海风光,而若找地 方或者回旅店换衣服就将赶不上游船。
如 何处理这件事情就是一个算法问题:是先上游船再在船上找地方换衣服,还是找个地方换衣服而放弃游览苍山洱海。显然不同的算法有着不同的收 益和代价。如果能够在游船上找到合适的地方更换衣服,则采用先上游船再换衣服的算法为佳;否则就是放弃游览的算法更好,因为如果冻病了显然就不划算了。最 后,我选择了在游船上更换衣服的算法:在游船上找到了一个贵宾室更衣。
图3 在蝴蝶泉水下洗个手也会涉及算法
算法由问题驱动
算 法的发现总是由相关的问题驱动的。拿排序来说,因为生活中到处都充满次序,每个人都要接受自己在某个次序里的位置。比如,各种排名、评 优、民意调查等,最后的结果都体现为一个次序!看来,“没有次序无以成方圆”并不是空穴来风!而谈到排序用的方法,人们很自然地想到插入法,因为这种朴素 的算法和人的思维方式非常类似:它就是人们打牌时整理手中扑克牌的算法。
但 是随着数据量的增大,插入排序的效率缺陷迅速变为人们无法容忍的缺点。于是人们发明了归并排序、堆排序、快速排序等,这些排序的方法大大 改善了速度,但是人们却并不满足于此。因此又发明了效率更高的线性排序。表1给出的是各种排序算法平均情况下的效率比较:最上面一行的数字代表输入的规 模,如10表示一共有10个数据项,1M表示一共有100万个数据项。其他格子里面的数据为相应算法在相应输入规模下完成排序所需要的时间,单位为毫秒。 所有输入数据为随机产生。
表1 部分排序算法的时间效率比较 (单位:毫秒)
排序算法 10 100 1K 10K 100K 1M
冒泡排序 0.000276 0.005643 0.545 61 8174 549 432
选择排序 0.000237 0.006438 0.488 47 4717 478 694
插入排序 0.000258 0.008619 0.764 56 5145 515 621
哈希排序/增量3 0.000522 0.003372 0.036 0.518 4.152 61
堆排序 0.00045 0.002991 0.041 0.531 6.506 79
归并排序 0.000723 0.006225 0.066 0.561 5.48 70
快速排序 0.000291 0.003051 0.030 0.311 3.634 39
基数排序/进制100 0.005181 0.021 0.165 1.65 11.428 117
基数排序/进制1000 0.016134 0.026 0.139 1.264 8.394 89
注:
- 算法运行环境为Intel 酷睿2双核E8400,3.0GHz,Windows 7*64。
- 本表数据由作者所授“数据结构”课的胡嘉斌同学测试所得。
一 个个新的算法都是为了解决前面算法遗留的问题而产生的。从表1里的数字可以看出,一般来说,随着新的算法的出现,排序效率在不断提高。不 过,虽然每个算法似乎解决了前面算法的遗留问题,但新的问题也会被有意或无意地引入。例如,线性排序虽然将排序的时间复杂性降低到线性级,但各种前提条件 极大地限制了其应用范围。也许这就是算法永远也不能或不会停止发展的一个原因吧。
算法是计算机的灵魂
因 为人不是全能的,一个时刻只能做一件事情,因此做事情就要有一个步骤。由于算法要满足人的这种特性,它通常被表示为一个做事情的行为序 列。因此,从一般意义上说,算法就是求解问题的步骤。由于计算机的计算操作完全是一步一步地进行,因此算法的上述性质用于计算机是再合适不过了,可以说算 法弥漫在计算机的一切行为上。如果说操作系统是计算机的心智,那么算法就是计算机的灵魂。
理解灵魂当然不是件容易的事情,由于它高度抽象与简洁,许多学生都望而却步。我们先看一个纸牌魔术(见图4):
- 任选一位观众将一副扑克牌充分洗好。
- 背对观众,请观众随机抽出一张牌,记住牌面,然后将这张牌放回整副牌的最上面。
- 接过牌后,洗牌几次。洗的时候保持最上面一张牌不动。
- 对观众说:“我来教你魔法,只要吹一口气,就能把刚才你抽的牌吹到任意位置上”。
- 请观众说出一个数字,比如说10,然后一边吹气,一边想着刚才说的数字10。
- 在吹完气后,请观众一张一张地将上面的牌取出放在桌上。
- 到第10张时,将牌翻开,发现并不是其原来抽的牌。
- 接回整副牌,并把上一个步骤里取出堆放在桌上的牌收起,仍放在整副牌的最上面。
- 然后洗牌几次,洗的时候保持上面放回来的那堆牌不动。
- 从观众手上拿回刚才翻开的那张牌,插入到最上面9个位置中的任意一个。
- 对观众说:“你刚才不是在想着那个数字的时候吹的气,而是在吹气的时候想着那个数字,而这是完全不同的两回事。我现在演示一下如何吹气”。对着牌吹一口气。
- 请观众从上到下数牌,到第10张时翻开。
- 这张翻开的牌就是观众一开始抽的那张牌。
图4 算法无处不在,就连纸牌魔术都有其背后支持的算法
读者看明白了上面的这个魔术了吗?这里面隐藏着一个算法。如果看懂了就可以在朋友面前一显身手了。当然,如果没有看懂也没有什么关系。算法本来就不是轻易让人看懂的嘛。
对于一些吹毛求疵的人来说,也许会说这个纸牌魔术不是算法。至少这跟我们研究算法的人所打交道的常见算法不太一样。这没有什么关系,来看下面的一段伪代码:
2 x←A[p] // A[p]被选中
3 i←p
4 for j←p+ 1 to q do
5 If A[j]≤ x then
6 i←i+ 1
7 A[i]?A[j] // 交换A[i]和A[j]的内容
8 A[p]?A[i]
9 return i
读者能看出来这个伪代码程序片段完成的是什么功能吗?
要分析一个算法,似乎就更难了。读者能看出下面的C程序片段里面“laugh++”语句执行多少次吗?
2 for (j= 1; j<=i; j++)
3 laugh++;
如 果这些问题读者都能回答,那恭喜你。看来算法分析对于你来说将是很容易的事情,不过可能也不一定。如果你回答不出这些问题,不用担心,因 为回答诸如此类的问题就是本书的目的。当然了,本书回答的远不止这么几个简单问题,而是会阐述更重要的算法精髓:算法思想、战略和分析!