已知值的完美哈希值

时间:2011-11-15 06:39:39

标签: c hash

假设我有一些已知的值,我想要创建一个哈希表。例如,

For 0x78409 -> 1
For 0x89934 -> 2
For 0x89834 -> 3

等...

但这些值(0x78409,0x89934,0x89834)仅在运行时已知,因此不能使用 switch / case 。但是,它们在执行开始时就已知,所以也许我们可以创建一个哈希函数,它可以自己调整以构成一个完美的哈希表。所以我的问题是,我们可以为这种情况创建一个完美的哈希函数。

3 个答案:

答案 0 :(得分:3)

如果在创建hashmap之前已知输入的整个域,那么这是可能的,但需要某种形式的运行时代码生成,通过VM或JIT(可能通过脚本语言,如LuaJIT),允许你使用gperf及其同类在运行时创建一个哈希,编译它,然后用它来填充和从地图中检索。

更简单,更可行的解决方案是对给定的输入排列集使用具有极低冲突的散列函数(例如:您可能只使用字母,小写字符),最小完美散列。

Murmur3和crapwow是值得关注的人(尽管我对crapwow持谨慎态度),Google's CityHashxxHash也值得关注。鲍勃詹金斯也有一个很好的基于最小完美哈希的地图here,这也应该做得很好。

答案 1 :(得分:1)

维基百科提供this page。但是你确定你想要一个完美的哈希函数吗?也许一个好的快速哈希函数就足够了?

答案 2 :(得分:0)

这些属性对您来说是否足够?:

  • 没有碰撞
  • 最坏情况键查找性能=> O(log n)

然后是概念验证实施:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_PAIRS 3
#define KEY_SIZE 20

#define VALUE_OR_KEY_NOT_FOUND(v) ((v==NULL)? "(__KEY_NOT_FOUND__)":v)

typedef struct {
    char Key[KEY_SIZE];
    char Val[KEY_SIZE];
} Pair;

typedef struct {
    unsigned int lastPairIndex;
    Pair pairs[MAX_PAIRS];
} HashTable;

int comparePairs(const void * a, const void * b)
{
  return strcmp(((Pair *)a)->Key, ((Pair *)b)->Key);
}

void hashInsert(HashTable * hashTable, char * key, char * val) {
  unsigned int ix = hashTable->lastPairIndex++;
  strcpy(hashTable->pairs[ix].Key,key);
  strcpy(hashTable->pairs[ix].Val,val);
}

void hashFinalize(HashTable * hashTable) {
  qsort(hashTable->pairs, MAX_PAIRS, sizeof(Pair), comparePairs);
}

char * hashLookup(HashTable * hashTable, char * key) {
  char * r = bsearch(key, hashTable->pairs, MAX_PAIRS, sizeof(Pair), comparePairs);
  if (r != NULL)
    return r + KEY_SIZE;
  return NULL;
}

int main()
{
    HashTable ht = {0};
    char * res;
    char * key_1 = "jkl";
    char * key_2 = "oops";

    hashInsert(&ht, "jkl", "some val");
    hashInsert(&ht, "def", "other val");
    hashInsert(&ht, "abc", "this val");
    hashFinalize(&ht);

    res = hashLookup(&ht, key_1);
    printf("\"%s\" key => value: \"%s\"\n", key_1, VALUE_OR_KEY_NOT_FOUND(res));
    res = hashLookup(&ht, key_2);
    printf("\"%s\" key => value: \"%s\"\n", key_2, VALUE_OR_KEY_NOT_FOUND(res));

    return 0;
}

未检查到许多错误 - 例如插入时 - 已经存在相同的密钥。这只是概念验证。由于密钥按字母顺序排序,因此可以使用二进制搜索算法执行密钥查找,从而实现O(log n)密钥查找性能。 HTH!