编程珠玑 第一部分 基础

1.开篇

这一章探讨了一个经典的问题,即所谓的磁盘文件排序或“外排序”。
书中提到了对内存大小使用大小有要求的程序设计的一个想法是使用分桶方法:
前提是待排序的数据是有一个取值范围,我们假设为[0,N]。并且数据的分布应为较均匀的。
将数据分成[0,M-1],[M,2M-1],[2M,3M-1]……[KM,N]这样的一系列区间。我们将遍历待排序数据,将值属于[0,M-1]的数据放入内存中,对内存中的数据进行排序。再遍历一次待排序数据,将值属于[M,2M-1]的数据读至内存排序。接下来一直重复这样的操作直至[kM,N]。
其中M是每次分桶所需的内存,M的值应是合理的。

如果待排序的数据都是整数,那么可以使用位图来排序。

2啊哈!算法

本章开头提出了3个问题

问题1.给定一个包含32位整数的顺序文件,它至多只能包含40亿个这样的整数,并且整数的次序是随机的。请查找一个此文件中不存在的32位整数。在有足够内存的情况下,你会如何解决这个问题?如果你可以使用若干外部临时文件但可用主存却只有上百字节,你会如何解决这个问题?

若按照上一章的思路,可以使用位图的方法来解决这个问题。但是这种方法若在内存不足的时候将不能使用。即使有虚拟内存,那也会导致大量的缺页。或者使用文件来保存位图文件?那也会浪费很多效率在读写文件中。

首先我们要明确问题:这是一个搜索问题,而不是排序!我们并不需要遍历整个文件。我们可以使用二分搜索来解决这个问题。假如有一个方法可以区分缺失的元素在不在一堆数据中。注意:此方法并不需要找出缺失的元素。那么我们就可以基于此方法使用二分搜索,在O(log2n)中解决这个问题。

那么这个方法是怎样的?首先考察所有整数的最高位,按照是0或1可以分为两类,如果有一类中整数的个数比另一类少,则我们可以肯定这一类中一定包含有我们希望寻找的缺失整数;如果两类个数相同,则随便选一类就可以了(因为假定最高位为0的一类没有缺失的整数,那它的个数一定超过了2^31, 那么最高位为1的一类的个数也超过了2^31, 由此知道这一类也没有缺失的整数,那就是说所有整数都存在,矛盾。)。选定之后,可以再在子类中考察第二位是0还是1,进一步分类。

2、将一个具有n个元素的一维向量向左旋转i个位置。例如,假设n=8,i=3,那么向量abcdefgh旋转之后得到向量defghabc。你只能使用1字节的辅助变量。

这个问题模拟了交换两个相邻且大小不同的内存块中的数据的问题,这个问题出现在例如文档中一段文字移动到另一段之前,需要较快的响应速度。

书中给出的结果简单暴力。利用求逆公式BA = (A^r B^r )^r,其中^r 表示求逆,即A = abc,A^r = cba。

3、给定一本英语单词词典,请找出所有的变位词集。例如,因为”pots” “stop” “tops”相互之间都是由另一个词的各个字母改变序列而构成的,因此这些词相互之间就是变位词。

将每个单词设置一个标签。在根据标签进行查找,标签为该单词中出现的字母的有序排列。如题目中”pots” “stop” “tops”的标签都为opst(按字母表顺序排序)。
这个问题引申出来对数据的特征进行排序。若我们希望将一些带有相同特征的数据集合到一起或排序,那么我们可以将其特征表示出来为标签,在按标签进行排序。这样可以得到数据的特征集中或排序。

优秀的程序员都有点懒,他们坐下来并等待灵机一动的出现而不急于使用最开始的想法编程。

3.数据决定程序结构

几个原则:
1、将重复性代码改写到数组中。
使用最简单的数据结构——数组——来表示一段冗长的相类似的代码往往能达到最佳效果。
(例如各种if 整合到数组中)
2、封装复杂的结构
当你需要一个复杂的数据结构时,使用抽象的术语对它进行定义,并将那些操作表示成一个类。
3、让数据去构造程序。
使用适当的数据结构去替换复杂的代码,这可以使数据起到构造某个程序的效果。
(在编写代码之前,好的程序员通常都会通篇理解构建程序时所围绕的输入数据结构、输出数据结构以及中间数据结构。)

程序员在节省空间方面无计可施时,将自己从代码中解脱出来,退回来并集中心力研究数据,常常能有奇效。(数据的)表示形式是程序设计的根本。

4.编写正确的程序

在实际编程过程中可以考虑插入assert断言,以确保对程序的准确理解。

5.编程小事

在程序中加入”脚手架”,以做到对函数准确地把握和理解。脚手架就是对程序功能的一个简要分割,可以在适当位置加入assert(bool)断言,或使用printf,以确保对程序的理解是正确的。

本篇文章参考了
http://blog.163.com/pang_bo_happy@126/blog/static/6890385820120102215360/

你可能感兴趣的:(编程珠玑)