有时候明明知道要这样去做,去学习,这样学习之后,会事半功倍,效率高。而当由于自己的懒惰或者其它情绪因素而做不到时,心里又懊悔又不知所措
人,或许就是有很多缺点,对自己要求很高,期待很高,有时候做不到,失望也就随之而来了
慢慢的进步吧
第一章 开篇
这一章揭示了本书的中心思想:对实例研究的深入思考不仅很有趣,而且可以获得实际的益处
第一章以一个问题开始,启发人们如何把问题的定义跟直接的程序设计技术结合起来,从而得到更好的解决办法。“怎样给一个磁盘文件排序”?当你听到时,你会怎么去解决呢?会马上想到归并排序吗?如果你想到了,也算一个解决思路。但是只是这样的一个问题,你有想过磁盘文件上的都是什么数据么?是整数,浮点数,还是字符串?显然对于你要真正排序的数据是很重要的。除了数据之外,还有一些其他的限制,比如,内存够不够大,能不能一次都读入内存,然后一起排序呢?如果可以一次读入内存,那就用常规的排序操作就可以了,比如:插入,快速,选择,冒泡等等。wait,当你要选择使用哪种算法的时候,有没有考虑到系统的整体要求呢?比如系统要求只能给你几十秒的时间,而你的算法却要几小时,几分钟,显然也是不能达到要求的。这些都是需要考虑的。
1.3 程序设计
排序,一个很常见的功能,有各种各样的算法来支持,但是文中提到了一些特殊的条件“在1M左右内存中,排序1千万个7位整数,每个整数都不重复”。如果用int数组来保存数据,那么只能保存250000个数。那么排序1千万个数,需要读写40次文件才能完成。例如:第一次读文件,用数组保存下0至250000之间的数,然后排序,写入输出文件,然后进行第二次读取,保存250001至500000之间的数,然后再排序,追加进输出文件中。。。。。
这是很容易想到的方法,是似乎有点麻烦,需要40次读取文件。有没有更加简单的方法呢?
1.4 实现概要
如果你仔细观察上面的“特殊条件”,那么在结合下面的方法,你就能很轻松的解决这个问题。
位图(位向量):用一个长字符串中的元素来表示一个集合中的第几位是否满足某种属性。例如有一个集合{1,2,4,5},就可以用{1,1,0,1,1}来表示。0表示该下标元素不存在,1表示该下表元素存在。在这个例子中,1、2、4、5均存在,而3不存在,所以集合中第三位为0,其他均为1(说简单一点,就是位图中第几位就表示数值几,然后用0,1来表示存在或不存在)。最后可以直接写成11011。
在这个问题中,每个整数不重复,范围是1到1千万,如果用1个二进制来表示1个数,为了表示1千万个数,那么就需要1千万个二进制 = 1百25万个字节 = 1.25M。在实现时,不同语言关于二进制位的实现不同(C++、Java中都有BitSet),这个就看各位了。
有了位图,剩下的就简单了,只要读入文件,比如第一次读到100,那么就把位图数组中的第100个元素设置为1(bit[100] = 1),表示100出现了,其他的以此类推。
最后,遍历位图数组,从0到1千万,如果数组中某位元素为1,那么输出该位(if bit[i] == 1 print i)
你看,这样不就实现了排序么?
1.5 原理
作者最后总结到
- 对小问题的分析有时候可以得到明显的益处。
- 正确的问题:明确了问题,这场战役就成功了90%。
- 多趟算法:假设现在内存限定1M,那么如何利用位图解决这个问题?(提示:将位图和40趟算法结合一下)
- 空间-时间折中与双赢:如果你选择对了数据结构或者设计方法,那么,你的程序可能在空间和时间上都得到优化。
- 简单的设计:“设计者确定某个设计达到完美的标准不是不能再增加任何东西,二是不能在减少任何东西”。简单的程序通常比具有相同功能的复杂程序更可靠、更安全、更健壮、更高效,而且更易于实现和维护。