改变了我人生轨迹的计算机科学奇书
2008 年,我还在混 Hi-PDA 论坛时,曾在里面求经典计算机书推荐,然后有个哥们推荐了 编程珠玑。
我信了,在 卓越 上搞了一本。
至今,我非常感谢那个哥们。
从某种程度上说,这本书改变了我人生的轨迹。
编程珠玑 第二章 啊哈算法 里面讲了三个算法题目,其中有第二题是字符串移位(例如:abcdef → defabc)
这道题我碰到两次:
- 第一次:2010 年考研,计算机专业课,最后一道编程大题(15 分貌似)。
- 第二次:2011 年微软实习面试,白板编程题目。
(这里也可以看出十年前远没有现在这么卷,字符串移位这种题目都能考研进微软)
编程珠玑是贝尔实验室 Jon Bentley (名字缩写 JB 似乎不雅,还是叫宾利叔高端些)在 ACM 通讯上的程序设计档搞的连载,由于宾利叔既有实力又有文采,编辑决定把这些连载整理成书。这就有了这本程序设计奇书——编程珠玑。
在可靠的工程之外,在洞察力和创造力范围内结晶而出的编程珠玑。正如自然界中的珍珠来自于磨砺牡蛎的细沙一样,这些编程珠玑来自于磨砺程序员的实际问题。
之所以说这本书是奇书,因为:
- 它既讲算法数据结构,又讲程序优化,还讲编程思想,甚至连程序正确性验证都有涉及。
- 书中代码极度优雅,既可读又高效还简洁,在我看过的书里,能和这本书代码匹敌的只有 K&R 的 The C Programming Language 和 STL 之父的 Elements of Programming。
- 书非常薄,也就二百来页,能把书写薄的都是狠人。
下面是我的摘录:
编程文献和理论中充斥着时间—空间的折中:通过使用更多的时间,可以减少程序所需的空间。例如,答案5中的两趟算法让程序运行时间加倍从而使空间减半。但我的经验常常是这样的:减少程序的空间需求也会减少其运行时间。
进行程序算法调优时,一般都会使用时空对换(time-space tradeoff):有时用空间换时间,比如缓存;有时有时间换空间,比如编码解码。
但有时程序之所以慢,是因为使用了错误的数据结构,或者对需求有误解。
这里举个我在 Facebook 做 Reaction (就是点赞)的例子:
Android 上性能很差,用户经常挂。
刚开始准备重新写 Reaction 缓存系统,但还好我抑制住了冲动。
一顿 code inspection + profiling 之后,我惊奇的发现 Android 本地存储的 Reaction 大的离谱,不到 16dp 的图标,却用了 256x256 的图片。
改了十来行,效率大幅提升,因为图片变小既降低了网络数据,又减少了 local cache 压力,所以 crash 也少了很多。
Antoine de Saint-Exupéry是法国作家兼飞机设计师,他曾经说过:“设计者确定其设计已经达到了完美的标准不是不能再增加任何东西,而是不能再减少任何东西。
代码评审,架构评审,装逼必用。
在20世纪80年代早期,洛克希德公司加利福尼亚州桑尼维尔市工厂的工程师们每天都要将许多由计算机辅助设计(CAD)系统生成的图纸从工厂送到位于圣克鲁斯市的测试站。虽然仅有40公里远,但使用汽车快递服务每天都需要一个多小时的时间(由于交通阻塞和山路崎岖),花费100美元。请给出新的数据传输方案并估计每一种方案的费用。
你会想到这帮工程师的解法是 放鸽子 么。
把图纸拍成胶卷然后用信鸽。
鬼才。
程序员的主要问题与其说是技术问题,还不如说是心理问题:他不能解决问题,是因为他企图解决错误的问题。问题的最终解决,是通过打破他的概念壁垒,进而去解决一个较简单的问题而实现的。
参考上面的 放鸽子。
提供充足的时间,竟然仅有约10%的专业程序员能够将这个小程序编写正确。但是他们不是唯一一批发现这个任务困难的人:Knuth在其The Art of Computer Programming, Volume 3: Sorting and Searching 的6.2.1节的历史部分中指出,虽然第一篇二分搜索论文在1946年就发表了,但是第一个没有错误的二分搜索程序却直到1962年才出现。
二分搜索写对确实很难。编程珠玑里的正确性验证为我打开了循环不变式的大门。
对这方面感兴趣的,可以读下 Tony Hoare 的 An Axiomatic Basis for Computer Programming,六页论文,读明白编程水平会提升一大截。
David Gries所著的Science of Programming 是程序验证领域里极佳的一本入门书籍,该书的平装本由Springer-Verlag出版社于1987年出版。这本书先讲逻辑,进而对程序验证和开发进行了正规的介绍,最后讨论了常见语言的编程问题。本章尝试勾勒出了程序验证的潜在好处;对多数程序员来说,要想高效地使用程序验证技术,唯一的办法就是研读一本类似Gries著作的书。
The Science of Programming 确实很好,不过有些烧脑,恐怕很少人能读的下去。
芝加哥的一个银行系统已经正确运行了好几个月,但是第一次用于国际数据就出现了非正常退出。程序员们花费了几天的时间来清理代码,但是他们没有发现任何导致程序退出的错误命令。当他们更深入地观察该现象时,发现当为厄瓜多尔这个国家输入数据时程序出现了非正常退出。更进一步的观察发现,当用户键入其首都的名字基多(Quito)时,程序将其解释为退出请求。
段子手
如果仅需要较小的加速,就对效果最佳的层面做改进。 对于效率,大多数程序员都有自己的下意识反应:“改变算法”或“调整排队规则”会脱口而出。决定在某一特定层面着手之前,请先考虑一下所有可能的设计层面,然后选择“性价比”最高的那一个:投入最小的精力就可以获得最大加速系数的那个设计层面。如果需要较大的加速,就对多个层面做改进。
非常精炼的总结。
不要着急写代码。
用现在的话术,就是先找到痛点。
经验法则 。我最初是在一节会计课上了解到“72法则”的。假设以年利率r %投资一笔钱y 年,金融版本的“72法则”指出,如果r ×y =72,那么你的投资差不多会翻倍。该近似相当精确:以年利率6%投资1 000美元12年,可得到2 012美元;以年利率8%投资1 000美元9年,可得到1999美元。
72 法则了解下。
因为John Roebling清楚地知道自己对哪些问题不了解。与设计布鲁克林大桥有关的笔记和信函现在还保存着,这些笔记和信函是优秀工程师了解自己知识局限性的很好的例子。他知道悬索桥有气动上升现象,并且进行了仔细的观察;但他也知道自己不清楚如何为之建模。于是他就将布鲁克林大桥车行道的托架的强度按照基于已知的静态和动态负荷的正常计算结果的6倍设计。此外,他还对延伸到车行道的斜拉网络进行了特别地设计,以加强整座桥的强度。看看这些方法,独一无二。
优秀的工程师的一个特点,是知道自己的局限性。相比之下一些新人往往会快速的做出一些看似能用但一进 prod 就拉跨的鬼东西出来。
简单性可以衍生出功能性、健壮性以及速度和空间。Dennis Ritchie和Ken Thompson最初在具有8 192个18位字的机器上开发出了Unix操作系统。他们在关于该系统的论文中说到“在系统及其软件方面,总是存在着相当严重的空间约束。如果同时对合理的效率和强大的能力提出要求,那么空间约束不仅具有经济上的意义,还会使设计更优雅一些。”
约束能带来更优秀的设计。
下面就是对程序员的10条建议。
解决正确的问题。
探索所有可能的解决方案。
观察数据。
使用粗略估算。
利用对称性。
利用组件做设计。
建立原型。
必要时进行权衡。
保持简单。
追求优美。
这十条建议适用于任何工程环境,甚至是人生决策。
尽管编程珠玑既有深度,又有广度,但我会推荐任何计算机水平的人去读:
- 在校学生可以从前几章学到算法和数据结构的知识
- 工程师可以从中学到程序设计理念和代码调优
- 营销号可以从中学到各种段子(放鸽子 只是其中一个)
奇书。满星。
以上。
严禁任何形式的搬运,我写书评,一方面记录,一方面分享,不是给营销号抄袭狗带流量。