《编程珠玑(第二版)》读书笔记——第一章

  慢慢的学习算法中。。。有时候明明知道要这样去做,去学习,这样学习之后,会事半功倍,效率高,而当由于自己的懒惰或者其它情绪因素而做不到时,心里又懊悔又不知所措。。。人,或许就是有很多缺点,对自己要求很高,期待很高,有时候做不到,失望也就随之而来了。。。慢慢的进步吧,不急不躁。

  这本书,有的读的比较认真有的读的比较粗略,写个读书笔记,再把这本书带给自己的收获记录下来吧。。。

  第一章:开篇

  第一章以一个问题开始,启发人们如何把问题的定义跟直接的程序设计技术结合起来,从而得到更好的解决办法。“怎样给一个磁盘文件排序”

  当你听到时,你会怎么去解决呢?会马上想到归并排序吗?如果你想到了,也算一个解决思路。但是只是这样的一个问题,你有想过磁盘文件上的都是什么数据么?是整数,浮点数,还是字符串?显然对于你要真正排序的数据是很重要的。除了数据之外,还有一些其他的限制,比如,内存够不够大,能不能一次都读入内存,然后一起排序呢?如果可以一次读入内存,那就用常规的排序操作就可以了,比如:插入,快速,选择,冒泡等等。wait,当你要选择使用哪种算法的时候,有没有考虑到系统的整体要求呢?比如系统要求只能给你几十秒的时间,而你的算法却要几小时,几分钟,显然也是不能达到要求的。这些都是需要考虑的。

  让我们继续了解题意,只有真正把握了题目要求,才能真正的根据要求选择合适的算法,题目的定义是很重要的,包括:题目的输入数据是什么,题目的要求,题意是什么。题目的输出是什么,要以怎样的格式输出。另外,这个题目本身的约束是什么?

  通过了解可以总结出:

  输入:一个最多包含n个正整数的文件,每个数都小于n,其中n=10的7次方,不允许有重复的,而且也没有其他的数据与之相联系。(数的大小,多少)

  输出:按升序排列输出到文件中。

  约束:最多有1M的内存空间可用,有充足的磁盘空间。运行时间最多几分钟,如果只有10秒,就不用优化了。(空间跟时间的约束)

  算法:

  1.可能最先想到的是归并排序,读入输入文件一次,然后在工作文件的帮助下完成排序并写入输出文件一次。工作文件需要多次读写。

    这个办法,归并排序本身的算法需要O(nlogn),然后还要有很多文件的读写操作,时间不符合条件。

  2.利用多趟算法,每次完成一步。因为这个待排序的数据都是整数,又根据内存1M的空间限制,可以分批读入数据然后分批排序分批读出。如果每个整数都用32位整数表示(即每个整数4个字节),那么1M的空间大概能存储250 000个整数,这样分40次就读入排序。第一次,将0—249 999之间的数据读入,然后利用快速排序,将这些数据(最多有250 000,因为不可能每个数据都有的嘿嘿)排序,然后输出到文件中。第二次,将250 000—499 999之间的数据读入内存,排序,输出。。。依次这样,就能完成所有数据的排序。

   然而,这需要40次读入输入文件,磁盘读取是很慢的,所以这个不算好的办法。

  3.位图数据结构。我们可以再次利用待排数据的特殊性,都是整数,所以出现了一种很巧妙的办法,就是利用位图这样的一种数据结构,比如,可以用10位长的字符串表示10以内的非负整数的集合。比如{1,3,5,8,9}则位图表示为:0,1,0,1,0,1,0,0,1,1

集合中有的,设置为1,集合中没有的设置为0,这样一次读取,就可以表示所有数据,并且按顺序输出,此时已经排好序了。

    这是个很巧妙的办法,没有了,一般排序的比较,移动的过程,明显效率会高很多,但是也有一定的限制:只有输入文件的所有整数都可以在可用的1M空间内表示的时候,才能用这种方法,否则是不行的。而且这个特殊的例子是必须是整数,而且范围比较小,而且没有重复,没有其他数据与之相联系。

    这个办法跟我之前写过的,基数排序,计数排序,桶排序,思路是很相像的。

  而有的时候这个办法是很有用的,一次输入,就能排好序,不用比较移动,但是好用的一般规矩比较多,比如二分查找。嘿嘿。

还有一个问题:就是如果数据无法在仅有的1M可用空间内表示,假如数据需要1.5M,那该怎样呢?显然此时,不能用位图数据结构了,只能用多趟算法了。

测试用例:包含100万个整数的文件,其中每个都小于1000万,比较了系统排序、C++/STL,C/qsort,位图的时空开销

 

               系统排序  C++/STL  C/qsort   位图

 总时间开销(秒)   89      38      12.6    10.7

 计算时间开销      79      28      2.4     0.5

 空间开销(MB)    0.8     70      4        1.25

 

尽管位图的办法,时空开销都比其他的少了一个数量级,但是这个的限制是灰常多的,但是一旦够条件,还是很好用的,而C++的虽然比C的要开销大,但是代码要短很多,因为C++/STL可以用set集合,可以直接调用函数即可,所以代码量很小。

 

课后都是此类题的变体,但还有一个比较不错的题:

商店允许客户通过电话订购商品,并在几天后上门取货,商店的数据库用客户的电话号码作为检索的关键字(客户知道她们自己的号码,而且每个号码都是唯一的),如何组织,可以高效的插入和检索操作?

此时,不能再考虑位图了,因为客户数量,你是不知道的,小了不够用,大了浪费。所以考虑其他的。这里说了,高效的插入和检索,主要还是查找么,高效的查找,一般考虑散列,如何利用散列呢,首先,号码的后两位几乎是随机的,而前几位则不是(想想你家跟邻居的座机号码),所以后两位就是现成的随机函数,然后构造10*10的数组,然后依次放入,如果有重复的,就依次放入。查找的时候,先定位到那里,然后对相同的(也就是冲突的部分)进行顺序检索。这样很高效,这就是经典的“用顺序搜索解决冲突的开散列”

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值