各种Hash函数冲突率分析 (三)

2014-11-24 03:28:17 · 作者: · 浏览: 3
uter Programming Volume 3》中展示而得名。
template
size_t DEKHash(const T* str)
{
if(!*str) // 这是由本人添加,以保证空字符串返回哈希值0
return 0;
register size_t hash = 1315423911;
while (size_t ch = (size_t)*str++)
{
hash = ((hash << 5) ^ (hash >> 27)) ^ ch;
}
return hash;
}
/// @brief FNV Hash Function
/// @detail Unix system系统中使用的一种著名hash算法,后来微软也在其hash_map中实现。
template
size_t FNVHash(const T* str)
{
if(!*str) // 这是由本人添加,以保证空字符串返回哈希值0
return 0;
register size_t hash = 2166136261;
while (size_t ch = (size_t)*str++)
{
hash *= 16777619;
hash ^= ch;
}
return hash;
}
/// @brief DJB Hash Function
/// @detail 由Daniel J. Bernstein教授发明的一种hash算法。
template
size_t DJBHash(const T *str)
{
if(!*str) // 这是由本人添加,以保证空字符串返回哈希值0
return 0;
register size_t hash = 5381;
while (size_t ch = (size_t)*str++)
{
hash += (hash << 5) + ch;
}
return hash;
}
/// @brief DJB Hash Function 2
/// @detail 由Daniel J. Bernstein 发明的另一种hash算法。
template
size_t DJB2Hash(const T *str)
{
if(!*str) // 这是由本人添加,以保证空字符串返回哈希值0
return 0;
register size_t hash = 5381;
while (size_t ch = (size_t)*str++)
{
hash = hash * 33 ^ ch;
}
return hash;
}
/// @brief PJW Hash Function
/// @detail 本算法是基于AT&T贝尔实验室的Peter J. Weinberger的论文而发明的一种hash算法。
template
size_t PJWHash(const T *str)
{
static const size_t TotalBits = sizeof(size_t) * 8;
static const size_t ThreeQuarters = (TotalBits * 3) / 4;
static const size_t OneEighth = TotalBits / 8;
static const size_t HighBits = ((size_t)-1) << (TotalBits - OneEighth);

register size_t hash = 0;
size_t magic = 0;
while (size_t ch = (size_t)*str++)
{
hash = (hash << OneEighth) + ch;
if ((magic = hash & HighBits) != 0)
{
hash = ((hash ^ (magic >> ThreeQuarters)) & (~HighBits));
}
}
return hash;
}
/// @brief ELF Hash Function
/// @detail 由于在Unix的Extended Library Function被附带而得名的一种hash算法,它其实就是PJW Hash的变形。
template
size_t ELFHash(const T *str)
{
static const size_t TotalBits = sizeof(size_t) * 8;
static const size_t ThreeQuarters = (TotalBits * 3) / 4;
static const size_t OneEighth = TotalBits / 8;
static const size_t HighBits = ((size_t)-1) << (TotalBits - OneEighth);
register size_t hash = 0;
size_t magic = 0;
while (size_t ch = (size_t)*str++)
{
hash = (hash << OneEighth) + ch;
if ((magic = hash & HighBits) != 0)
{
hash ^= (magic >> ThreeQuarters);
hash &= ~magic;
}
}
return hash;
}
我对这些hash的散列质量及效率作了一个简单测试,测试结果如下:

测试1:对100000个由大小写字母与数字随机的ANSI字符串(无重复,每个字符串最大长度不超过64字符)进行散列:

字符串函数 冲突数 除1000003取余后的冲突数
BKDRHash
0 4826
SDBMHash
2 4814
RSHash
2 4886
APHash
0 4846
ELFHash
1515 6120
JSHash
779 5587
DEKHash
863 5643
FNVHash
2 4872
DJBHash
832 5645
DJB2Hash
695 5309
PJWHash
1515 6120

测试2:对100000个由任意UNICODE组成随机字符串(无重复,每个字符串最大长度不超过64字符)进行散列:

字符串函数 冲突数 除1000003取余后的冲突数
BKDRHash
3 4710
SDBMHash
3 4904
RSHash
3 4822
APHash
2 4891
ELFHash
16 4869
JSHash
3 4812
DEKHash
1 4755
FNVHash
1 4803
DJBHash
1 4749
DJB2Hash
2 4817
PJWHash
16 4869

测试3:对1000000个随机ANSI字符串(无重复,每个字符串最大长度不超过64字符)进行散列:

字符串函数 耗时(毫秒)
BKDRHash
109
SDBMHash
109
RSHash
124
APHash
187
ELFHash
249
JSHash
172
DEKHash
140
FNVHash
125
DJBHash
125
DJB2Hash
125
PJWHash
234

结论:也许是我的样本存在一些特殊性,在对ASCII码字符串进行散列时,PJW与ELF Hash(它们其实是同一种算法)无论是质量还是效率,都相当糟糕;例如:"b5"与“aE",这两个字符串按照PJW散列出来的hash值就是一样的。 另外,其它几种依靠异或来散列的哈希函数,如:JS/DEK/DJB Hash,在对字母与数字组成的字符串的散列效果也不怎么好。相对而言,还是BKDR与SDBM这类简单的Hash效率与效果更好。

其他:

作者:icefireelf


常用的字符串Hash函数还有ELFHash,APHash等等,都是十分简单有效的方法。这些函数使用位运算使得每一个字符都对最后的函数值产生 影响。另外还有以MD5和SHA1为代表的杂凑函数,这些函数几乎不可能找到碰撞。

常用字符串哈希函数有 BKDRHash,APHash,DJBHash,JSHash,RSHash,SDBMHash,