Nil*_*nck 17
对于固定的字符串集,请使用gperf.
如果您的字符串集更改,您必须选择一个哈希函数.之前讨论过这个话题:
使用hash_map时,在stl字符串上使用的最佳散列算法是什么?
Chr*_*oph 17
还有一个很好的文章在eternallyconfuzzled.com.
Jenkins对字符串的一次性哈希应该如下所示:
#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;
}
Run Code Online (Sandbox Code Playgroud)
根据您的用例,可能更好的另一种解决方案是实习字符串.这就是符号在Lisp中的工作方式.
实习字符串是一个字符串对象,其值是实际字符串字节的地址.因此,您通过检入全局表来创建一个实习字符串对象:如果字符串在那里,则将实习字符串初始化为该字符串的地址.如果没有,则插入它,然后初始化您的实习字符串.
这意味着从同一个字符串构建的两个实习字符串将具有相同的值,即地址.因此,如果N是系统中实习字符串的数量,则特征为:
干杯,
卡尔
对于一个好的主题来说,永远不晚,我相信人们会对我的发现感兴趣。
我需要一个哈希函数,在阅读了这篇文章并对此处给出的链接进行了一些研究后,我想出了 Daniel J Bernstein 算法的这种变体,我用它做了一个有趣的测试:
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;
}
Run Code Online (Sandbox Code Playgroud)
这种变体对字符串进行哈希处理,忽略大小写,这满足了我对用户登录凭据进行哈希处理的需要。“clave”在西班牙语中是“钥匙”。我对西班牙语感到抱歉,但它是我的母语,程序是用它写的。
好吧,我编写了一个程序,它将生成从“test_aaaa”到“test_zzzz”的用户名,并且为了使字符串更长,我在这个列表中添加了一个随机域:“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 等。
这是测试的输出 -“Colision entre XXX y XXX”表示“XXX 和 XXX 的碰撞”。“palabras”的意思是“单词”,“总计”在两种语言中都是相同的。
布斯坎多科利西内斯... “test_phiz@hotmail.com”和“test_juxg@cloud-nueve.com”之间的冲突 (1DB903B7) “test_rfhh@hotmail.com”和“test_fpgo@yahoo.com”之间的冲突 (2F5BC088) “test_wxuj@hotmail.com”和“test_pugy@cloud-nueve.com”之间的冲突 (51FD09CC) “test_sctb@gmail.com”和“test_iohw@cloud-nueve.com”之间的冲突 (52F5480E) “test_wpgu@cloud-nueve.com”与“test_seik@yahoo.com”之间的冲突 (74FF72E2) “test_rfll@hotmail.com”和“test_btgo@yahoo.com”之间的冲突 (7FD70008) “test_wcho@cloud-nueve.com”与“test_scfz@gmail.com”之间的冲突 (9BD351C4) “test_swky@cloud-nueve.com”与“test_fqpn@gmail.com”之间的冲突 (A86953E1) “test_rftd@hotmail.com”和“test_jlgo@yahoo.com”之间的冲突 (BA6B0718) “test_rfpp@hotmail.com”和“test_nxgo@yahoo.com”之间的冲突 (D0523F88) “test_zlgo@yahoo.com”和“test_rfdd@hotmail.com”之间的冲突 (DEE08108) 碰撞总数:11 帕拉布拉斯总数:456976
这还不错,456,976 次碰撞中有 11 次(当然使用完整的 32 位作为表长度)。
使用 5 个字符(即从“test_aaaaa”到“test_zzzzz”)运行程序,实际上会耗尽构建表的内存。下面是输出。“No hay memoria para insertar XXXX (insertadas XXX)”的意思是“没有剩余内存可插入 XXX (XXX已插入)”。基本上 malloc() 在那一点上失败了。
没有插入“test_epjcv”的干草记忆(插入 2097701)。 布斯坎多科利西内斯... ...451'碰撞'字符串... 碰撞总数: 451 帕拉布拉斯总数:2097701
这意味着 2,097,701 个字符串上仅发生 451 次碰撞。请注意,在任何情况下,每个代码的冲突次数都不会超过 2 次。我确认这对我来说是一个很好的哈希,因为我需要将登录 ID 转换为 40 位唯一 ID 以进行索引。因此,我使用它将登录凭据转换为 32 位哈希,并使用额外的 8 位来处理每个代码最多 255 次冲突,从测试结果来看,几乎不可能生成这些冲突。
希望这对某人有用。
编辑:
就像测试盒是 AIX 一样,我使用 LDR_CNTRL=MAXDATA=0x20000000 来运行它,以给它更多的内存,并且运行时间更长,结果如下:
Buscando Colisiones... 碰撞总数: 2908 帕拉布拉斯总数: 5366384
经过 5,366,384 次尝试后,即为 2908!
非常重要:使用 -maix64 编译程序(因此无符号长整型为 64 位),所有情况下冲突次数均为 0!