仅使用标准英文字母和下划线,最多可以使用多少个字符而不会在散列表/字典中发生潜在的冲突。
因此,像以下字符串:
blur
Blur
b
Blur_The_Shades_Slightly_With_A_Tint_Of_Blue
...
仅使用标准英文字母和下划线,最多可以使用多少个字符而不会在散列表/字典中发生潜在的冲突。
因此,像以下字符串:
blur
Blur
b
Blur_The_Shades_Slightly_With_A_Tint_Of_Blue
...
不能保证单个字母之间不会发生冲突。
你可能不会遇到冲突,但string.GetHashCode
中使用的算法没有具体说明,且可能会更改。(特别是在.NET 1.1和.NET 2.0之间就有所变化,这给那些假设它不会变化的人带来了问题。)
请注意,哈希码冲突不会阻止精心设计的哈希表正常工作-您仍然应该能够正确获取值,只是可能需要使用相等性检查多次检查多个具有相同哈希码的键。
任何依赖哈希码唯一性的字典都缺少关于哈希码的重要信息,我认为如此 :) (除非它在绝对知道它们将是唯一的非常特定的条件下运行,即它正在使用完美哈希函数。)
假设你有一个完美哈希函数(通常情况下不会有,正如其他人所提到的),你可以按照以下方式找到最大可能的字符数,以确保没有两个字符串会产生冲突:
l
(或更短)的字符串具有总共54 ^ l
个表示。请注意,基数为54而不是53,因为字符串可以在任何字符之后终止,每个字符增加一个额外的可能性-不过这并不会对结果产生很大影响。54 ^ l = 2 ^ 32
解决它:log2 (54 ^ l) = 32
l * log2 54 = 32
l = 32 / log2 54 = 5.56
假设采用最优的通用哈希(1),为长度为H
位的哈希函数计算S
个长度为L
且每个字符有W
位的字符串在哈希表中发生冲突的概率,可以根据哈希表大小(即桶数)'N'来计算冲突概率。
H
位完美地分割到可用的桶N
(3)中。这意味着H
除了作为N
的限制外,变得无意义。
W
和'L'只是S
的上界基础。为了简化数学运算,假设字符串长度小于L
的字符串仅用特殊的空字符填充到L。如果我们对最坏情况感兴趣,则为54^ L
(26 * 2 + '_' + null),显然这是一个荒谬的数字,实际条目数比字符集和长度更有用,因此我们将简单地按照S
是自己的变量来处理。
我们试图将S
个项目放入N
个桶中。这就成为了一个非常著名的问题,生日悖论。回想一下长度为L
的54 ^ L
个字符串的限制。然而,我们只有H
位(我们将假设为32位),大约有40亿个不同的数字。因此,如果您可以拥有真正的任何字符串和任意数量的字符串,则必须满足以下要求:
54 ^ L <= 2 ^ 32
并解决它:
log2 (54 ^ L) <= 32
L * log2 54 <= 32
L <= 32 / log2 54 <= 5.56
由于字符串长度显然不能是分数,因此您只能拥有最大长度为5。确实非常短。
如果您知道您将只拥有一组字符串,其大小远低于40亿,则完美散列将使您能够处理任何L
的值,但在实践中限制值集可能非常困难,您必须提前知道所有这些值,否则就会退化为字符串 ->哈希的数据库,并在遇到新字符串时添加到其中。
对于这个练习,通用哈希是最优的,因为我们希望减少任何碰撞的概率,即对于任何输入,它从一组可能性 R 中产生输出 x 的概率为 1/R。
请注意,对哈希(和内部桶)进行最优化处理相当困难,但您应该期望内置类型在合理的情况下是可行的,尽管不总是理想的。
在这个例子中,我避免了闭散列和开散列的问题。这确实与所涉及的概率有关,但影响不大。