具有32位整数低冲突率的快速string散列algorithm

我有很多不相关的命名的事情,我想快速search。 一个“Aardvark”在任何地方都是一个“土豚”,所以对这个string进行散列和重新使用这个整数对于加快比较速度是很有效的。 整套名称是未知的(随着时间而改变)。 什么是快速string哈希algorithm,将生成小(32或16)位值,并具有低冲突率?

我想看看特定于C / C ++的优化实现。

其中一个FNV变体应该符合您的要求。 它们速度很快,并且产生相当均匀分布的输出。

穆尔哈什是相当不错的。

对于一个固定的string集使用gperf。

如果你的string集更改,你必须select一个哈希函数。 之前已经讨论过这个话题:

当使用hash_map时,在stlstring上使用什么最好的散列algorithm?

在eternalconfuzzled.com还有一篇不错的文章 。

jenkins的一次性string散列应该看起来像这样:

#include <stdint.h> uint32_t hash_string(const char * s) { uint32_t hash = 0; for(; *s; ++s) { hash += *s; hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return hash; } 

另一个可能更好的解决scheme取决于你的用例是internedstring 。 这就是符号如何在Lisp中工作。

internedstring是一个string对象,其值是实际string字节的地址。 所以你通过检查一个全局表来创build一个实际的string对象:如果string在那里,你需要将实例化的string初始化为该string的地址。 如果没有,则插入它,然后初始化您的实习string。

这意味着从同一个string构build的两个string将具有相同的值,这是一个地址。 因此,如果N是系统中的实际string的数量,则其特征为:

  • 缓慢的build设(需要查找和可能的内存分配)
  • 在并发线程的情况下需要全局数据和同步
  • 比较是O(1),因为你比较地址,而不是实际的string字节(这意味着sorting工作正常,但它不会是一个字母sorting)。

干杯,

卡尔

你为什么不使用Boost库? 他们的散列函数很容易使用,Boost中的大部分内容很快就会成为C ++标准的一部分。 有些已经是了。

加速哈希是一样容易

 #include <boost/functional/hash.hpp> int main() { boost::hash<std::string> string_hash; std::size_t h = string_hash("Hash me"); } 

你可以在boost.orgfind提升

看看GNU gperf 。

Hsieh哈希函数是相当不错的,并且有一些基准/比较,作为C中的一般哈希函数。取决于你想要什么(这不是完全显而易见的),你可能需要考虑类似cdb的东西。

鲍勃jenkins有许多哈希函数可用 ,所有这些都是快速和低冲突率。

对于一个好的学科来说,这绝对不会迟到,我相信人们会对我的发现感兴趣。

我需要一个散列函数,在阅读了这篇文章并对这里给出的链接进行了一些研究之后,我想出了Daniel J Bernsteinalgorithm的这种变化,我曾经做过一个有趣的testing:

 unsigned long djb_hashl(const char *clave) { unsigned long c,i,h; for(i=h=0;clave[i];i++) { c = toupper(clave[i]); h = ((h << 5) + h) ^ c; } return h; } 

这种变化散列string忽略情况,这适合我需要散列用户login凭据。 “clave”是西class牙语中的“关键”。 我很抱歉西class牙语,但我的母语和程序写在它上面。

那么,我写了一个程序,将生成用户名从'test_aaaa'到'test_zzzz',并使string更长 – 我添加到这个列表中的随机域名:'cloud-nueve.com','yahoo.com ','gmail.com'和'hotmail.com'。 因此,他们每个人看起来像:


 test_aaaa@cloud-nueve.com,test_aaab@yahoo.com, 
 test_aaac@gmail.com,test_aaad@hotmail.com等。

以下是testing的输出结果:“XXX”和“XXX”的意思是“碰撞XXX和XXX”。 “palabras”的意思是“文字”和“总数”在两种语言中都是相同的。


     Buscando Colisiones ...
     colision entre'test_phiz@hotmail.com'y'test_juxg@cloud-nueve.com'(1DB903B7)
     Colision entre'test_rfhh@hotmail.com'y'test_fpgo@yahoo.com'(2F5BC088)
     Colision entre'test_wxuj@hotmail.com'y'test_pugy@cloud-nueve.com'(51FD09CC)
     Colision entre'test_sctb@gmail.com'y'test_iohw@cloud-nueve.com'(52F5480E)
     Colision entre'test_wpgu@cloud-nueve.com'y'test_seik@yahoo.com'(74FF72E2)
     Colision entre'test_rfll@hotmail.com'y'test_btgo@yahoo.com'(7FD70008)
     colision entre'test_wcho@cloud-nueve.com'y'test_scfz@gmail.com'(9BD351C4)
     Colision entre'test_swky@cloud-nueve.com'y'test_fqpn@gmail.com'(A86953E1)
     Colision entre'test_rftd@hotmail.com'y'test_jlgo@yahoo.com'(BA6B0718)
     Colision entre'test_rfpp@hotmail.com'y'test_nxgo@yahoo.com'(D0523F88)
     colision entre'test_zlgo@yahoo.com'y'test_rfdd@hotmail.com'(DEE08108)
    合计:11
     Total de Palabras:456976

这还不错,在456,976中有11次碰撞(使用完整的32位长度作为表长度)。

使用5个字符(即从'test_aaaaa'到'test_zzzzz')运行程序实际上会耗尽构build表的内存。 以下是输出。 '没有干草memoria para插入XXXX(insertadas XXX)'的意思是'没有剩余的内存插入XXX(XXX插入)'。 基本上malloc()在那个时候失败了。


    没有hay memoria para插入'test_epjcv'(insertadas 2097701)。

     Buscando Colisiones ...

     ... 451'colision'串...

    共和国总数:451
     Total de Palabras:2097701

这意味着在2,097,701个string上只有451个冲突。 请注意,在任何情况下,每个代码都有两个以上的冲突。 我确认这是一个伟大的散列对我来说,因为我需要的是将loginID转换为一个40位唯一的ID索引。 所以我使用它来将login凭证转换为32位散列,并使用额外的8位来处理每个代码多达255次的冲突,这在testing结果中看起来几乎是不可能产生的。

希望这对某人有用。

编辑:

像testing框是AIX,我运行它使用LDR_CNTRL = MAXDATA = 0x20000000给它更多的内存,它运行时间更长,结果在这里:

Buscando Colisiones … Total de Colisiones:2908 Total de Palabras:5366384

在5,366,384次尝试之后,这是2908!

非常重要 :用-maix64编译程序(所以unsigned long是64位),所有情况下的冲突数是0!

你可以看到.NET使用reflection器的String.GetHashCode()方法。

我猜测微软花了相当多的时间来优化这个。 他们也打印了所有MSDN文档,以便随时更改。 很显然,这是在他们的“性能调整雷达”;-)

对于C ++来说,我也会这么想:

在上一个问题中有一些很好的讨论

以及如何挑选哈希函数的一个很好的概述,以及这里几个常见的分布统计

这里描述的是一个简单的方法来实现它自己: http : //www.devcodenote.com/2015/04/collision-free-string-hashing.html

post的一个片段:

如果说我们有一个大写英文字母的字符集,那么字符集的长度是26,其中A可以用数字0表示,B用数字1表示,C用数字2表示,以此类推直到Z 25.现在,无论何时我们想将这个字符集的string映射到一个唯一的数字,我们执行与二进制格式相同的转换

CRC-32 。 谷歌大约有一万亿个链接。