我最近阅读了这篇Throw away the keys: Easy, Minimal Perfect Hashing文章,内容涉及为一组已知的密钥生成最小的完美哈希表。
本文似乎假设您需要一个中间表。如果我们假设键的集合很小(即<64),还有其他更简单的方法来生成这样的函数。
就我而言,我想将一组线程ID:s映射到数组中的唯一数据块。线程在生成哈希函数之前启动,并在程序运行期间保持不变。确切的线程数有所不同,但在程序运行时保持不变:
unsigned int thread_ids*;
unsigned int thread_count;
struct {
/* Some thread specific data */
}* ThreadData;
int start_threads () {
/* Code which starts the threads and allocates the threaddata. */
}
int f(thread_id) {
/* return unique index into threadData */
}
int main() {
thread_count = 64; /* This number will be small, e.g. < 64 */
start_threads();
ThreadData[f(thread_ids[0])]
}
答案 0 :(得分:1)
是的,您可以在运行时构建最小完美哈希函数(MPHF)。您可以使用多种算法,但是大多数算法实现起来有点复杂,因此我无法为您提供有效的示例代码。许多是在cmph project中实现的。
最简单的一个可能是BDZ。在较高的级别上,查找需要计算3个哈希函数和3个内存访问。如果内存不是问题,则只需2。它支持数百万个密钥。该算法需要一个查找表,该查找表大约是条目数的1.23倍。
还有其他算法,我自己发明了一种算法the RecSplit algorithm,但是我没有C实现,现在只有Java。基本上,这些算法找到了一种方法(以递归方式)将集合拆分为子集,直到子集大小为1。您需要记住如何拆分。实际上,最简单的解决方案是使用查找表“如何拆分”,但是该表确实很小,对于64个键来说可能只有5个整数。第一个划分为16个子集的4个子集,第4个子集将每个子集映射到数字0..15。
(如果您严格不需要 minimum 完美的哈希函数,而只是一个 perfect 哈希函数,则我添加了第二个答案。构造更简单,查找很多更快,但需要更大的数组。)
答案 1 :(得分:0)
您可以使用蛮力搜索如下构建 perfect 哈希。对于64个条目,目标数组的大小至少应为512个条目,否则搜索将在合理时间内找不到索引。
那么完美的哈希函数就是murmur(x + perfectHashIndex) & (TARGET_SIZE - 1)
#include <stdio.h>
#include <stdint.h>
#include <string.h>
static uint64_t murmur64(uint64_t h) {
h ^= h >> 33;
h *= UINT64_C(0xff51afd7ed558ccd);
h ^= h >> 33;
h *= UINT64_C(0xc4ceb9fe1a85ec53);
h ^= h >> 33;
return h;
}
// must be a power of 2
#define TARGET_SIZE 512
static uint64_t findPerfectHashIndex(uint64_t *array, int size) {
uint64_t used[TARGET_SIZE / 64];
for (uint64_t index = 0; index < 1000;) {
memset(used, 0, TARGET_SIZE / 64 * sizeof(uint64_t));
for (size_t i = 0; i < size; i++) {
uint64_t x = murmur64(array[i] + index) & (TARGET_SIZE - 1);
if (((used[x >> 6] >> (x & 63)) & 1) != 0) {
goto outer;
}
used[x >> 6] |= 1UL << (x & 63);
}
return index;
outer:
index++;
}
// not found
return -1;
}
int main() {
int size = 64;
uint64_t ids[size];
for(int i=0; i<size; i++) ids[i] = 10 * i;
uint64_t perfectHashIndex = findPerfectHashIndex(ids, size);
if (perfectHashIndex == -1) {
printf("perfectHashIndex not found\n");
} else {
printf("perfectHashIndex = %lld\n", perfectHashIndex);
for(int i=0; i<size; i++) {
printf(" x[%d] = %lld, murmur(x + perfectHashIndex) & (TARGET_SIZE - 1) = %d\n",
i, ids[i], murmur64(ids[i] + perfectHashIndex) & (TARGET_SIZE - 1));
}
}
}