C:为大型数据集生成哈希键?

时间:2013-02-14 19:44:44

标签: c hash key

我目前正在玩哈希和密钥生成试图创建自己的哈希密钥生成器。

目前我有一个约90000个字符串的列表(每个1个字和一个不同的字)。我想知道生成密钥(数字键不是字符串键)的最佳方法是什么?

目前,根据最后一个ascii字符,我会根据字母的值进行计算。

结果是大约50%的单词生成一个与另一个单词冲突的单词。

我使用二次探测然后在表格中找到其余单词的空间。

我的问题,如上所述,通常是为90000个不同单词生成密钥的最佳方式?我知道数据集越大,冲突的可能性就越大,但你会如何建议/或最大限度地减少冲突呢?

编辑:另外 - 我不关心密码学,它只需要快速。

感谢。

5 个答案:

答案 0 :(得分:4)

您可以“借用”Java's implementation of String's hashCode *

int hashCode(const char* s) {
    int h = 0;
    while (*s) {
        h = 31*h + (*s++);
    }
    return h;
}

此函数实现了合理的分离,并且是最广泛使用的散列函数之一。

* as it turns out,Java反过来"borrowed" from Kernighan & Ritchie's book关于C编程。

答案 1 :(得分:4)

为了防止冲突,你需要一个好的哈希密钥生成器。

有几种算法可供选择。最近的一个非常快的称为xxHash。它是用C语言编写的。

答案 2 :(得分:0)

选择90,000大小的哈希表是不错的选择,有更好的完美哈希概念,根据这个使用双哈希一个用于表查找而另一个用于维护列表,你应该尝试乘法方法,我认为这是个好主意。

答案 3 :(得分:0)

我见过Knuth使用:

  register int h,k; register char *p;
  for (h=0,p=w;*p;p++) h=(*p+h+h)%hash_prime;

其中hash_prime是大于哈希表中预期的实际条目数的4倍的素数。

请参阅:Knuth's literateprogramming.com,冒险示例。

这是上下文中的散列代码:

#define hash_prime 1009/* the size of the hash table */

typedef struct {
  char text[6]; /* string of length at most 5 */
  char word_type; /* a |wordtype| */
  char meaning;
} hash_entry;

hash_entry hash_table[hash_prime]; /* the table of words we know */

void new_word(w,m)
  char *w; /* a string of length 5 or less */
  int m; /* its meaning */
{
  register int h,k; register char *p;
  for (h=0,p=w;*p;p++) h=(*p+h+h)%hash_prime;
  while (hash_table[h].word_type) {
    h++;if (h==hash_prime) h=0;
}

int lookup(w)
  char *w; /* a string that you typed */
{
  register int h; register char *p; register char t;
  t=w[5]; w[5]='\0'; /* truncate the word */
  for (h=0,p=w;*p;p++) h=(*p+h+h)%hash_prime; /* compute starting address */
  w[5]=t; /* restore original word */
  if (h<0) return -1; /* a negative character might screw us up */
  while (hash_table[h].word_type) {
    if (streq(w,hash_table[h].text)) return h;
    h++;if (h==hash_prime) h=0;
  }
  return -1;
}

注意,这段代码:

  register char t;
  // . . .
  t=w[5]; w[5]='\0'; /* truncate the word */
  // . . .
  w[5]=t; /* restore original word */

特定要求是仅查看前5个字符,应删除,以便对整个单词进行散列。

答案 4 :(得分:0)

你想要的术语是雪崩 - 一种提供最佳传播的哈希函数。

如果您希望保证您的密钥是唯一的,并且您的数据集没有重复 然后你可以将你的单词转换为base36号码到base10号码。如果使用stroull(),则可以返回非常大的整数

char *p=myword;
for(; *p; p++) 
  *p=toupper(*p);
unsigned long long key=strtoull(myword, NULL, 36);

这可能会溢出并仍然返回正数。给定长字符串时的某些散列可能溢出32位整数。 Kerneghan的哈希和伯恩斯坦的哈希就是这样做的。

实际上,正如其他几个人所指出的那样:

考虑冲突是hash_table大小和hash_function modulo hash_table大小的雪崩的函数。您想要的不是真正独特的键,而是更好的hash_table算法和大小。