HASH表
HASH表是很典型的key - value结构,我们根据key,经过哈希函数y = h(x),得到value的存放地址以便访问value.稍微严格一些,可以如下描述HASH表,根据设定的HASH函数H(key)和处理冲突的方法,将一组关键字(定义域)映射到一个有限的,连续的空间(值域)中,并以关键字在值域中的值作为value的存储位置,这种表就叫做HASH表。映射的过程称为HASH散列
HASH表两个关键工作:
1. HASH函数的确定2. 冲突的解决
衡量HASH函数的标准
1.产生的碰撞率,产生的碰撞越小,说明HASH函数的分布越均匀,利用KEY根据HASH函数进行查找时就越快。2.HASH函数本身的效率,HASH函数必须简单快速,如果HASH函数本身就要耗费大量的时间,那丧失了HASH表本身的优点。
设计HASH函数的方法:
1.基于加法和乘法的散列
这种方式是通过遍历数据中的元素然后每次对某个初始值进行加操作,其中加的值和这个数据的一个元素相关。通常这对某个元素值的计算要乘以一个素数。看下面的公式,可以发现,每次乘了一个参数,然后进行叠加
![](http://static.oschina.net/uploads/space/2012/0720/222803_IdNR_100374.bmp)
2.基于移位的散列
基于移位的散列是利用字符串中的每个元素,进行移位操作。通常是结合左移和右移,移的位数的也是一个素数。每个移位过程的结果进行累加,最后移位的结果作为最终结果。下图就是对第i为数据进行左移和右移,在对单次结果进行累加,得到最终的HASH码
![](http://static.oschina.net/uploads/space/2012/0720/221240_GZ7S_100374.bmp)
在REDIS中,有一个HASH函数,根据内容可以发现,主要是基于移位的散列
/* Generic hash function (a popular one from Bernstein).
* I tested a few and this was the best. */
unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
unsigned int hash = 5381;
while (len--)
hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */
return hash;
}
该函数根据字符串缓冲区的内容以及长度生成了一个HASH数据。
/* Thomas Wang's 32 bit Mix Function */
unsigned int dictIntHashFunction(unsigned int key)
{
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
这个是根据整数,来生成HASH码
解决冲突的办法
1. 开放定址法,对冲突的结果加上一个增量再次计算,可线性探测再散列,二次探测再散列
2. 再HASH法,当利用一个HASH函数冲突后,换个HASH函数算个值
3. 链地址法(比较常用的方法)
2. 再HASH法,当利用一个HASH函数冲突后,换个HASH函数算个值
3. 链地址法(比较常用的方法)
解决冲突的办法,就是采用链表法,直接挂载到后面链表末尾就OK。若有H(key1) = H(key2), 那么key1和key2就
都挂载同一个链表下~(REDIS中就采用了这种方法)
参考:该片文章介绍了大量的HASH算法,具体内容可以操作这篇博客:
http://blog.csdn.net/eaglex/article/details/6310727