“怎样给一个磁盘文件排序?”

这是《编程珠玑》 第一章开篇的一个提问。第一眼看到这个问题,脑海里是不是出现了各种冒泡排序、归并排序、快速排序算法,准备“大展身手”一番?然而正如作者接下来说的一样,这样做往往导致一上来就犯错误,错就错在马上回答了这个问题。


搞清楚问题再回答

工作中发现身边很多人,包括我自己,都很容易陷入开篇这样的误区,拿到一个问题就急着解决,而没有经过仔细思考。或者,如果你是那个提出问题的人,你真的“把问题讲清楚”了吗?

回到开头的问题,当我们拿到一个问题时,先搞清楚对方为什么要这么问。

“怎样给一个磁盘文件排序?”

“为什么要自己给文件排序,而不用系统提供的排序?”

“排序只是大系统中的一个功能,因为特殊原因,不能用系统自带的排序”

“排序的内容是什么?文件有多少条记录?每条记录的格式是什么?是否有重复?为什么不用内存排序,要用磁盘排序?”

“排序的内容是7位的电话号码,最多有1000万条,没有重复,因为一些特殊原因,只有1MB内存能使用,但磁盘空间有富余”

现在我们搞清楚真正的问题了,他确实需要给磁盘文件排序,用通用的归并排序算法可以解决,但因为内存的限制,需要多次读取工作文件,势必会造成性能的下降。本着 特殊问题特殊分析 的原则,对于特定的需求,我们需要提供针对性的解法。


解决问题

位图

可以用如下10位的位数组(或字符串)来表示集合 {1,2,5,8}

1
0 1 1 0 0 1 0 0 1 0

解决问题

  1. 用一个长度为 1000万 的位数组,一开始全部初始化为 0
  2. 读取电话号码文件,对每一个电话号码,都在位数组对应的下标标记为 1。 (例如,电话号码 800-1705,就将数组的第 8001705 位置为1
  3. 遍历数组,对于标记为 1 的数组下标输出

这样,我们就得到一个排好序的电话号码文件啦。回过头来,是不是发现这个解决方式非常巧妙?所以,作为提问者,学会提问是一门学问,作为回答者,不要一上来就急于回答,先搞清楚真正的问题所在,最后,用简单的设计来解决问题

编程之外,亦是如此。