多姿多彩的哈希表
自从通过数据结构课程学习哈希表以来,对于哈希表的实现一直都是固定的课本上的理论,使用链表作为冲突消解策略,分配一个数组作为哈希表的基本结构,基本上实现哈希表的方法就是这样,但是一般因为找不到好的哈希函数而放弃使用哈希表。由于使用的少,对于哈希表的具体实现方式就没有花太多心思,就是使用哈希表基本上就是直接把库里的哈希表结构拿来使用,
最近学习了 berkely DB 和 sqlite3 的源代码,其它收获不说,单单哈希表的使用与实现就让我长了见识,至于 berkely DB 中对哈希表的使用和实现,适合于对磁盘文件信息的组织,在《 Berkeley DB 1.8.6 源代码学习》中已经总结,本文主要将 sqlite3 中已经看到的对哈希表的几种使用和组织方式总结一下,以备不时只需, sqlite3 中对哈希表的使用和组织方式适用于在内存中使用;
1 、经典实现
在对 sqlite3_pcache 接口的缺省实现 PCache1 结构中使用了哈希表来组织和管理缓冲区中的页面,主要在 pcache1.c 中出现,基本的实现方式就是同理论方式一样,使用一个数组组织哈希表,冲突消解策略使用的是链表;
哈希表 apHash 是一个 PgHdr1 类型指针的数组,使用页面编号作为键值,哈希函数是键值除以数组的长度;
如果需要增加哈希表的尺寸(数组的长度),那么需要将表中的元素重新插入,不同于在 berkely DB 中只用重新插入对应的桶中的部分项,但是由于是在内存中使用,不用考虑磁盘的读写,这样处理简单可行;
2 、伸缩型哈希表
这里所谓的伸缩性的哈希表其实就是在数据量较小的时候使用双向链表存储,当数据量大的时候该用哈希表存储;这在一些类库中具有对应的数据结构供直接使用, sqlite3 中使用了其中的一种实现;
这种哈希表的使用在 sqlite3 中较为广泛,作为一个单独的模块来实现, hash.h 和 hash.c 文件用于实现这一哈希表;
哈希表结构为 Hash :
使用四个成员变量存储:
htsize :无符号短整型,当使用哈希表存储时,哈希表中桶的数量;
count :无符号短整型,哈希表中入口项的个数(记录的个数);
first : HashElem 类型,哈希元素指针,指向入口项双向链表的表头;
ht : _ht 结构指针,哈希表存储结构,当使用哈希表存储时,将表现为一个桶的数组;含有两个成员变量,其中 count 成员变量记录本桶中记录的数量, chain 成员变量指向桶内记录链表的表头,哈希表使用的冲突消解策略是链表;
关于 Hash 的使用,当存储的记录数量较少时,将 htsize 赋值为 0 , ht 赋值为空,所有记录实际保存在以 first 为表头的双向链表中, count 是记录的数量;
当记录数量达到一定的程度后,使用 ht 配合哈希访问, htsize 记录了<