数据结构
散列表本质上是一个定长数组 + 一个散列函数,函数起索引的作用。
O(1) 的查找复杂度是通过数组的 FindKth 来实现的,即散列函数的一次运算可以得出元素的数组下标。
为了设计通用的散列结构,往往键的名字空间会给的非常大,甚至是不限的。而值的空间则一定是有限的,所以不管怎样的散列函数,碰撞的现象一定会发生。所以表里元素一般都是存一个链表,链表的元素里保留键值对,这样在散列运算之后再执行一次列表查找。当然此时就不是严格 O(1) 的了,而是与哈希表的填充度有关。
rehash
从空间上考虑,在不知道一个哈希表将会有多少数据的情况下(键值型数据库的典型情况),稳妥的做法是先给一个小空间,然后在填充度超过一定阀值的时候加大这个空间。
既然空间大小有变,必然一部分元素的散列值也会跟着变。这个将元素移动到新空间的过程就是 rehash。当然 rehash 既可以是扩展,也可以是收缩。
如 redis 默认会给 Hash 类型分配一个大小为 4 的数组空间,当填充度超过 100% 时,自动将空间扩展为大于等于2倍现有元素数量的最小 2<sup>n</sup> 数。
rehash 的过程如果发生在内存或单块硬盘里,那么可以很方便的处理。但如果是在分布式硬盘里,那么这个过程就有优化的必要了。应当尽量保证每个硬盘都能分配到均等的移动任务。
散列函数
同样因为输入键的不确定性,散列函数必须要保证输出(整数)在输出空间上的随机均匀分布。在此基础之上,算的越快越好~
一份散列函数的简介:
http://www.oschina.net/translate/state-of-hash-functions