最早看编程珠玑是由于上研时一位大牛同学的推荐,书很薄,但是却用了很长时间看完,因为书中写的内容确实非常好,对得起「珠玑」二字。将当时的读书笔记整理如下。
第十三章 : 搜索
该章节解决的问题是用集合从n个数值里选择m的问题.
构造了下面几种set:
- 线性表的set
- 链表的set
- 二分搜索树BST的set
- 位图的set
- 箱序列的set
链表和线性表比起来, 可以不用花时间调整元素, 因为数据都是线性存放的, 所以使用链表直接查找, 不需要进行移位操作.
二分搜索类似STL实现的set, 基于O(logm*m)的算法来实现.
位图set就是根据位图来判断一个元素是否存在。获取所有元素需要遍历所有元素, 所以时间是O(n).
最nb的来了. 考虑到数据具有如下特点:
- 取得m个数值, 每一个数值是均匀采样的.
- 数据最都只有m个.
如果我们将n的数值范围分为m个箱子, 每一个箱子表示一个range的数值, 那么因为是等概率采样, 所以每一个箱子中的数据冲突不会很多, 在每一个箱子中使用一个链表来表示所有的冲突元素即可.
m比较小的时, 可以认为每一个箱子只有一个元素, 所有时间复杂度和空间都是O(m).
插入元素: O(1) 查找元素: O(1) 遍历元素: O(m)
本质上这是一种hash, 但是通用的hash算法, 没有这么好的时间和空间.
下面的代码实现了上面所有的数据结构, 另外需要注明在实现中的几个细节点:
- 使用
reverse recursive insert
的方式插入元素, 这个方法可以用在链表中, 也可以用在 BST中.
原理是一个插入操作当前元素的下一个节点(或者是左右子树)等于其子元素执行完成了 插入操作之后的返回值, 当前的返回值就是执行完成了插入操作之后, 最上层的节点.
因为链表在插入和BST的插入都有一个特点, 需要保存上一个元素的数值, 这样子插入一个元素 之后才可以建立和之前的联系, 维持数据结构特性, 如果使用循环写就比较麻烦, 需要保存上一个 元素的数值, 而使用递归, 上一个元素就是当前递归的元素, 而其子节点通过返回值返回.
- 另一种nb的方法实现插入: 使用指针的指针, 狸猫换太子.
既然我们遍历的时候需要保存在一个指针的数值, 然后改变这个指针指向元素的数值, 那么 我们可以直接保存指向上一个元素指针的指针, 然后直接改变该指针指向元素的数值, 就变相 的建立了和之前元素的联系.
比如一个元素的地址为0x1234, 但我们保存指向0x1234的指针的地址为0x4567, 那么我们直接改变0x4567指向的内容, 就改变了前一个节点和后一个节点的对应关系!
- 哨兵节点非常有用
这里知道当前选择元素的范围一定是小于n的, 所以搜索都可以加入一个哨兵节点, 在循环时不需要溢出的判断, 因为最后一个元素一定结束循环, 这样子代码更简洁.
- 更高效的运算.
对于分箱操作, 或者是bitset中每一个运算单元长度, 尽量使用2的幂, 这样子除法更快!
- 减少内存的分配.
由于我们知道最多需要多少个节点, 所以一次性的分配节点, 然后按需使用可以大大提高速度!
Talk is cheap, show me the code.
|
第十四章 : heap
书中给出的heap实现代码确实是很美妙, 简单, 有效.
-
浪费了data[0]的空间用来保存sentinel, 在上调堆的时候, 将sentinel设置为最小值(如果为最小堆), 这样子 在上调堆的过程中, 不会超过该元素
-
使用从1开始下边对heap进行操作, 特别的方便, 不需要考虑+1和-1的问题.
-
上调堆和下调堆都是基于一个for循环, 不断的和父亲节点和子节点进行比较, 同时, for的结束条件也是 当前的父节点或者子节点是否还存在, 以及是不是不需要交换了, 因为已经符合heap的要求了.
-
在for实现的过程中, 一边幅值子节点的数值(或者父节点), 一边就行比较, 代码真心简洁!
代码如下:
|
第十五章 : 字符串
基于编程珠玑第15章节的随机文本生成算法:
实现的细节说明:
- 使用后缀树保存所有
k相邻连续单词
为基本单元的后缀树. - 初始时刻每一个后缀数组都是保存一个单词的开始地址指针.
- 以每一个单词为单位, 如果k个单词完全相同, 那么任何两个子串相同.
- 这样子规则排序得到的单元具有
k相邻连续单词
的性质, 在后缀数组中相邻的元素, 具有相似的k个单词性质 - 使用k阶单词生成方法, 表示使用前面k个单词来推导后面的第(k+1)的生成单词.
- 假设随机的k个单词作为前缀, 然后生成第k+1个单词, 下一个的前缀是在之前前缀的基础上移动一个单元格距离, 直到 无法生成新的k+1单元格为止.
- 产生新的k+1单词使用了随机生成算法, 每次找到一个相同的k前缀, 就随机的选择其中一个数值.
- 使用传统的二分不能够找到第一个相同的元素, 自己体会代码中的二分写法.
nb的代码实现啊!!! :
/* 保存当前所有输入的字符 */ |