此书的叙述模式是借由一个具体问题来引出的一系列算法,数据结构等等方面的技巧性策略。共分三篇,基础,性能,应用。每篇涵盖数章,章内案例都非常切实棘手,解说也生动有趣。

自个呢也是头一次接触编程技巧类的书籍,而且算法数据结构方面的知识储备实在是薄弱,这么看来,纯粹找虐啊orz。今此行为,歇业养伤,实属无聊。也可说是自打毕业后,看书如打仗,自视身处“安安稳稳的和平年代”,闲来了也就闲着,忧患意识甚少,有也退退缩缩。话说回来,这本书不像CLRS那种难打的硬仗(现在想想都脑仁疼啊),《Programming Pearls》这么个好对手,排烦解闷也正好练练身手!

废话了一大堆,嘿嘿,看官轻拍。那下面就来看看第一章讲了些啥~

问题

怎样给一个最多包含1千万条记录且每条记录都是7位的整数的磁盘文件排序?

准确描述

这里书本对问题抽象出了精确的描述:

输入:一个最多包涵n个正整数的文件,每个数都小于n,其中n=10^7。如果在输入文件中有任何整数重复出现就是致命错误。没有其他数据与该整数相关联。

输出:按升序排列的输入整数的列表。

约束:最多有(大约)1MB的内存空间可用,有充足的磁盘存储空间可用。运行时间最多几分钟,运行时间为10秒就不需要进一步优化了。

解决方案

  1. 归并排序。联想下归并排序的缺点:需要O(n)的辅助空间,可知他必将多次的多写一块额外的工作文件or内存。优势:只需读取一次。劣势:需要数次操作额外文件。

  2. 分批读入数据,然后使用快速排序。每个整数用32位即4字节表示最多可表示带符号的2^31-1>9 999 999,计算10^7/(10^6/4)可得,40次读取排序可以达到目标。优势:快。劣势:多次读取数据,多趟算法。

  3. 使用位图数据结构。这个一个(10^7/32 + 1) 行 (32) 列的大表:

    31 30 ... 1 0
    31 30 ... 1 0
    ......
    31 30 ... 1 0
    31 30 ... 1 0

  如果数据是{2,3,5},那么第一行上就会是:0000 0000 0000 0000 0000 0000 0010 1100。很明显的,文件里所有的整数都可以在这张表里找到对应的位置,聪明如你,这就是一个大小为10^7/32 + 1的int[],具体的算法是这样的:

package chpt1;

import java.util.List;

/**
* Created by wqi on 2016/10/22.
*/
public class BitSort {
// 位向量,也可称作位图,这里为了形象化,取作bitMap.
private int[] bitMap; // i >> 5即每32个数为一组,也就是数组重的一个int元素。 i & 0x1f 相当于取该数对32取模,就找到了该数对应的位,|= 即为置1。
private void set(int i) {
this.bitMap[i >> 5] |= (1 << (i & 0x1f));
} // 和set()本质上的区别就是 &= 将该数对应的位置0
private void clr(int i) {
this.bitMap[i >> 5] &= ~(1 << (i & 0x1f));
} // 返回该数对应的位为1或为0
private int test(int i) {
return (this.bitMap[i >> 5] & (1 << (i & 0x1f)));
} public void sort(List<Integer> list) {
this.bitMap = new int[list.size() / 32 + 1]; for (int i = 0; i < this.bitMap.length; i++) {
clr(i);// 第一阶段将所有的位都置为0。
}
for (int i = 0; i < list.size(); i++) {
set(list.get(i));// 第二阶段读入文件中的每个整数来建立集合,将每个对应的位都置为1。
}
for (int i = 0; i < list.size(); i++) {
if (test(i) == 1){
// 第三阶段检验每一位,如果该位为1,则输出这个数。
}
}
}
}

优势:只需要读取一次文件数据,且不需要额外文件。而且使用的是基本的位操作,速度会更快。劣势:没有,这算法相当友好。

总结  

这一章在英文原版中名为 Cracking the Oyster ,直译为「美妙的(也可作开裂的)牡蛎」。和开篇概览中提到的『对实例研究的深入思考不仅很有趣,而且可以获得实际的益处』很贴切,牡蛎多鲜啊,pearls 的美也很直观的看到。再扯句题外话,貌似在西方国家 Oyster 这个词的意味是很好的,沙翁的台词中有 the world is my oyster 意译可表示成——我可以为所欲为啦。

位图这种数据抽象确实很有趣!巧妙的解决了这种看上去很乍乎的大数据问题。在网上也了解到,很多时候在处理大批量数据时,都可以考虑使用该数据结构,这点往后有待补充,希望在这再写几篇做到『举一隅,不以三隅反』。另外,针对位图这一数据概念,Java已经有操作起来非常简单的实现了,就是BitSet(),该集合类初始范围在0~63(JDK Version: 1.8.0_101),如果这时候BitSet().set(64),它会自动扩容至当前容量的翻倍,也就是*2,在这即0~127。

就先写到这,2016年10月22日16:56:01。课后习题部分是很依赖对前文的理解,且变化不是太大,书后答案代码部分大都是用C/C++写的,但只会Java的我看起来也不麻烦(看到qsort好羡慕C系的程序员啊),明天看看有没有有意思的题目再补充吧。#明日债明日还#

;-)

【读书笔记】《编程珠玑》第一章之位向量&位图的更多相关文章

  1. 编程珠玑第一章的算法,Java实现,通俗易懂

    该算法也就是所谓的位图算法,用一个int表示32位,也就是实际值为1~32的数. 按照书里说的, 该算法只适合内存有限,而磁盘和时间不限,且数字在1~MAX之间不重复的排序. package demo ...

  2. 读书笔记http之第一章

    http TCP/IP协议各层: 应用层 决定了向用户提供应用服务时通信的活动. 比如 : FTP(FileTransferProtocol,文件传输协议)和DNS(DomainNameSystem, ...

  3. 《Android开发艺术探索》读书笔记 (13) 第13章 综合技术、第14章 JNI和NDK编程、第15章 Android性能优化

    第13章 综合技术 13.1 使用CrashHandler来获取应用的Crash信息 (1)应用发生Crash在所难免,但是如何采集crash信息以供后续开发处理这类问题呢?利用Thread类的set ...

  4. SQL Server2012 T-SQL基础教程--读书笔记(8 - 10章)

    SQL Server2012 T-SQL基础教程--读书笔记(8 - 10章) 示例数据库:点我 CHAPTER 08 数据修改 8.1 插入数据 8.1.1 INSERT VALUES 语句 8.1 ...

  5. 《Android开发艺术探索》读书笔记 (3) 第3章 View的事件体系

    本节和<Android群英传>中的第五章Scroll分析有关系,建议先阅读该章的总结 第3章 View的事件体系 3.1 View基本知识 (1)view的层次结构:ViewGroup也是 ...

  6. JavaScript DOM编程艺术第一章:JavaScript简史

    本系列的博客是由本人在阅读<JavaScript DOM编程艺术>一书过程中做的总结.前面的偏理论部分都是书中原话,觉得有必要记录下来,方便自己翻阅,也希望能为读到本博客的人提供一些帮助, ...

  7. 《Android开发艺术探索》读书笔记 (9) 第9章 四大组件的工作过程

    第9章 四大组件的工作过程 9.1 四大组件的运行状态 (1)四大组件中只有BroadcastReceiver既可以在AndroidManifest文件中注册,也可以在代码中注册,其他三个组件都必须在 ...

  8. [书籍翻译] 《JavaScript并发编程》第一章 JavaScript并发简介

    > 本文是我翻译<JavaScript Concurrency>书籍的第一章,该书主要以Promises.Generator.Web workers等技术来讲解JavaScript并 ...

  9. [Java编程思想] 第一章 对象导论

    第一章 对象导论 "我们之所以将自然界分解,组织成各种概念,并按其含义分类,主要是因为我们是整个口语交流社会共同遵守的协定的参与者,这个协定以语言的形式固定下来--除非赞成这个协定中规定的有 ...

随机推荐

  1. Linux sort 命令

    - 今天的收获: sort -t $'\t' 说明:sort 加-t 参数时,如果需要以 '\t' 分隔,需要写成上述形式.

  2. BZOJ 4184: shallot

    Description 在某时刻加入或删除一个点,问每个时刻的集合中能异或出来的最大值是多少. Sol 线段树+按时间分治+线性基. 按时间分治可以用 \(logn\) 的时间来换取不进行删除的操作. ...

  3. mysql 日期查询 总结

    1,对一天24小时内每小时的数据量求和: SELECT IFNULL(SUM(CASE HOUR(时间字段) WHEN 0 THEN 1 ELSE 0 END),0)as '0', IFNULL(SU ...

  4. C# I/O

    获取运行时的动态目录 private static string GetDataDir_Data() { var parent = Directory.GetParent(Directory.GetC ...

  5. PHP window下安装Spl_Types模块

    1. Window下,Spl_Types的模块的下载地址:http://pecl.php.net/package/SPL_Types/0.4.0/windows 2. php的可执行文件已经加到系统的 ...

  6. css单位盘点

    css单位有:px,em,rem,vh,vw,vmin,vmax,ex,ch 等等 1.px单位最常见,也最直接,这里不做介绍. 2.em:em的值并不是固定,它继承父级元素的字体大小,所以层数越深字 ...

  7. Python之Web前端jQuery扩展

    Python之Web前端: 一. jQuery表单验证 二. jQuery扩展 三. 滚动菜单 一. jQuery表单验证: 任何可以交互的站点都有输入表单,只要有可能,就应该对用户输入的数据进行验证 ...

  8. js学习进阶中-bind()方法

    有次面试遇到的,也是没说清楚具体的作用,感觉自己现在还是没有深刻的理解! bind():绑定事件类型和处理函数到DOM element(父元素上) live():绑定事件到根节点上,(document ...

  9. RSA原理及生成步骤

    摘自:http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html(可到原网址查看秘钥生成原理) RSA算法原理(一) 因为它是 ...

  10. javaScript判断浏览器类型

    <script type="text/javascript"> function getBrowserInfo(){ var OsObject=navigator.us ...