我目前正在玩哈希和密钥生成试图创建自己的哈希密钥生成器。
目前我有一个约90000个字符串的列表(每个1个字和一个不同的字)。我想知道生成密钥(数字键不是字符串键)的最佳方法是什么?
目前,根据最后一个ascii字符,我会根据字母的值进行计算。
结果是大约50%的单词生成一个与另一个单词冲突的单词。
我使用二次探测然后在表格中找到其余单词的空间。
我的问题,如上所述,通常是为90000个不同单词生成密钥的最佳方式?我知道数据集越大,冲突的可能性就越大,但你会如何建议/或最大限度地减少冲突呢?
编辑:另外 - 我不关心密码学,它只需要快速。
感谢。
答案 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算法和大小。