描述
我有一组相当大的(字符串,字符串,字符串)唯一元组(大约 4000 万,但可以变得更大)。对于每个元组,我计算一个无符号整数值。我想将这些值存储在某个地方,以便在生成它们之后可以重用它们(即使在应用程序出现故障之后,内存存储也是不可能的,不幸的是数据库也是如此)。
起初,我将它们作为元组(字符串、字符串、字符串、值)存储在一个文件中,但读取 4000 万条记录需要时间(而且我几乎立即需要它)。
我决定首先计算每个 (string, string, string) 元组的哈希值,然后将其标准化为 [0, n] (其中n是值的数量)并仅将值以排序顺序存储在二进制文件中(按标准化哈希值排序)。之后,我可以简单地 mmap() 这个文件并使用 mmap[normalize(hash(string, string, string))] 获取值。
我的哈希函数非常简单但速度很快,适用于我的情况(没有注意到任何冲突):
concatenatedString = s1+"."+s2+"."+s3
unsigned int hash = 31;
for(int i = 0; i < concatenatedString.length(); i++) {
hash = hash * 101 + (unsigned int) concatenatedString[i];
}
与归一化相同(直截了当):
((long) n * hash) / max_value
n - 我的归一化范围的上限(所以大约 4000 万,我取 n 不是 (n - lower_bound) 因为 lowe_bound = 0)
max_value - 旧集合的最大值(在我的情况下为 UINT_MAX,min_value = 0 所以我不将它包含在等式中)
问题
我的哈希函数不会产生 0 到 4,294,967,295(无符号整数)范围内的均匀分布的值(看不出它是如何做到的)。因此,在规范化之后,我有很多冲突导致数据丢失(覆盖相同数组索引下的值)。
有没有什么聪明的方法可以做我想做的事但没有那些冲突?
我完全知道可能会发生一些碰撞。问题是我的方法往往过于频繁地发生。我的散列范围比我的元素数量大 100 倍,所以我猜可能有办法做到这一点,但我还没有弄清楚怎么做。
解决方案 最后我将哈希更改为 Murmurhash,将我的规范化方法更改为简单的“模 newRange”并更改文件的格式(我现在存储所有数据(字符串字符串值)) - 文件现在很大但多亏了这一点,我才能够实现一个简单的碰撞检测机制(双散列)。