摘自网络:http://blog.minidx.com/2008/01/27/446.html,添加了些注释。
哈希算法将任意长度的二进制值映射为固定长度的较小二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希都将产生不同的值。要找到散列为同一个值的两个不同的输入,在概率上是极其微小的,所以数据的哈希值可以检验数据的完整性。
链表查找的时间效率为O(N),二分法为log2N,B+Tree为log2N,但Hash链表查找的时间效率为O(1)。
设计高效算法往往需要使用Hash链表,常数级的查找速度是任何别的算法无法比拟的,Hash链表的构造和冲突的不同实现方法对效率当然也会有一定的影响,然而Hash函数是Hash链表最核心的部分,下面是几款经典软件中使用到的字符串Hash函数实现,通过阅读这些代码,我们可以在Hash算法的执行效率、离散性、空间利用率等方面有比较深刻的了解。
下面分别介绍几个经典软件中出现的字符串Hash函数。
// 推荐
// PHP 中出现的字符串Hash函数
static unsigned long hashpjw(char *arKey, unsigned int nKeyLength)
{
// check
if ((arKey == NULL) || (nKeyLength <= 0)) return 0;
unsigned long h = 0;
unsigned long g = 0;
char *arEnd = arKey+nKeyLength;
while (arKey < arEnd)
{
h = (h << 4) + *arKey++;
if ((g = (h & 0xF0000000))) // 处理溢出值
{
h = h ^ (g >> 24);
h = h ^ g;
}
}
return h;
}
// 推荐
// OpenSSL 中出现的字符串Hash函数
unsigned long lh_strhash(char *str)
{
// check
if (str == NULL) return 0;
unsigned long ret = 0;
int i, len;
unsigned short *sTemp;
len = (strlen(str)+1)/2;
sTemp = (unsigned short *)str;
for (i=0; i<len; i++)
ret ^= (sTemp[i]<<(i&0x0f)); // 1:异或^,没有溢出;最大左移16位,也没有溢出;
return ret;
}
/* The following hash seems to work very well on normal text strings
* no collisions on /usr/dict/words and it distributes on %2^n quite
* well, not as good as MD5, but still good.
*/
unsigned long lh_strhash(const char *s)
{
// check
if ((s == NULL) || (*s == '