Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 简单散列函数_C_Function_Hashtable_String Hashing - Fatal编程技术网

C 简单散列函数

C 简单散列函数,c,function,hashtable,string-hashing,C,Function,Hashtable,String Hashing,我正在尝试编写一个C程序,该程序使用哈希表存储不同的单词,我需要一些帮助 首先,我创建一个素数大小的哈希表,它与我必须存储的单词数最接近,然后我使用哈希函数为每个单词找到一个地址。 我从最简单的函数开始,将字母相加,结果是88%的冲突。 然后我开始用这个函数做实验,发现不管我把它改成什么,碰撞都不会低于35%。 现在我正在使用 unsigned int stringToHash(char *word, unsigned int hashTableSize){ unsigned int cou

我正在尝试编写一个C程序,该程序使用哈希表存储不同的单词,我需要一些帮助

首先,我创建一个素数大小的哈希表,它与我必须存储的单词数最接近,然后我使用哈希函数为每个单词找到一个地址。 我从最简单的函数开始,将字母相加,结果是88%的冲突。 然后我开始用这个函数做实验,发现不管我把它改成什么,碰撞都不会低于35%。 现在我正在使用

unsigned int stringToHash(char *word, unsigned int hashTableSize){
  unsigned int counter, hashAddress =0;
  for (counter =0; word[counter]!='\0'; counter++){
    hashAddress = hashAddress*word[counter] + word[counter] + counter;
  }
  return (hashAddress%hashTableSize);
}
这只是我提出的一个随机函数,但它给了我最好的结果——大约35%的碰撞

在过去的几个小时里,我一直在阅读有关散列函数的文章,我尝试使用一些简单的函数,例如djb2,但所有这些函数都给了我更糟糕的结果。(djb2导致37%的冲突,这并不是更糟,但我期待更好的结果,而不是更糟) 我也不知道如何使用其他一些更复杂的参数,比如杂音2,因为我不知道它们接受的参数是什么(key、len、seed)

即使使用djb2,碰撞率超过35%是正常的,还是我做错了什么? 键、len和seed值是什么?

试试sdbm:

hashAddress = 0;
for (counter = 0; word[counter]!='\0'; counter++){
    hashAddress = word[counter] + (hashAddress << 6) + (hashAddress << 16) - hashAddress;
}
不过,这只适用于2种尺寸的电源。如果使用模,2个大小的幂只能买到东西,如果散列是一个非常糟糕的散列,具有非常糟糕的“位分布”。错误的位分布通常是由不使用任何类型的位移位(
>

首先,我创建一个素数大小的哈希表,它与我必须存储的字数非常接近,然后我使用哈希函数为每个字找到一个地址

返回(哈希地址%hashTableSize)

由于不同散列的数量与单词的数量相当,因此您不能期望发生低得多的冲突


我用一个随机散列做了一个简单的统计测试(这是你能达到的最好结果),发现如果你有不同的散列,26%是限制冲突率。

。有这么多冲突,你的散列表(即散列的最大有效长度)可能太低,或者您的算法/实现有问题。使用固定表而不是动态表(例如,使用32位或64位哈希作为键的树)有什么具体原因吗?例如,性能?查找复杂性?@Mario我使用的是带有直接链接的动态表,当它太满时会重新刷新自身(或者太空了)。我不使用树的原因是我在做一个专注于哈希表的课程。对于一个具有100%负载因子的最优哈希函数,冲突的预期分数为1/e:=.3678。因此,在这方面,你的函数是最优的。它可能对某些类型的输入敏感(例如带有固定前缀或固定后缀,这在现实生活中非常常见,例如:文件名、URL)没有移位的普通异或往往会导致非常糟糕的哈希。@JonathanLeffler:取决于数据。但在ASCII和逐字符处理的情况下,您可能是对的。将删除此建议。我的函数会给我36,5%的冲突。sdbm-37%djb2-37 Alder32-39%:(谢谢anyway@Hardell请确保您的哈希表足够大。如果哈希表的填充率超过70-80%,则会发生大量冲突!如果要添加100个字,哈希表的大小应至少为130到140,越大越好(例如200)。如果使用模(
%
)要将散列裁剪为哈希表大小,正如您所做的那样,不需要2倍大小的幂。仅当您要使用AND(
&
)时,才需要2倍大小的幂要裁剪散列,就像和比模运算快好几倍。@Hardell:我想你一定有一个错误的信念,认为好的散列表应该是无冲突的。事实恰恰相反。即使是世界上最伟大的专家编写的最好的散列表实现,在充满现实生活时也会有很多冲突数据。这是绝对不可避免的。每个索引只有两到四个冲突是一个很好的值,我不明白你为什么会抱怨。问题在于你如何处理冲突,而不是如何避免冲突。请参阅我在回答中添加的关于冲突的评论。
hashAddress = 5381;
for (counter = 0; word[counter]!='\0'; counter++){
    hashAddress = ((hashAddress << 5) + hashAddress) + word[counter];
}
uint32_t adler32(const void *buf, size_t buflength) {
     const uint8_t *buffer = (const uint8_t*)buf;

     uint32_t s1 = 1;
     uint32_t s2 = 0;

     for (size_t n = 0; n < buflength; n++) {
        s1 = (s1 + buffer[n]) % 65521;
        s2 = (s2 + s1) % 65521;
     }     
     return (s2 << 16) | s1;
}

// ...

hashAddress = adler32(word, strlen(word));
x % 4  == x & 3
x % 8  == x & 7
x % 16 == x & 15
x % 32 == x & 31
...
#include <stdint.h>
#include <stdlib.h>

#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))

#define mix(a,b,c) \
{ \
  a -= c;  a ^= rot(c, 4);  c += b; \
  b -= a;  b ^= rot(a, 6);  a += c; \
  c -= b;  c ^= rot(b, 8);  b += a; \
  a -= c;  a ^= rot(c,16);  c += b; \
  b -= a;  b ^= rot(a,19);  a += c; \
  c -= b;  c ^= rot(b, 4);  b += a; \
}

#define final(a,b,c) \
{ \
  c ^= b; c -= rot(b,14); \
  a ^= c; a -= rot(c,11); \
  b ^= a; b -= rot(a,25); \
  c ^= b; c -= rot(b,16); \
  a ^= c; a -= rot(c,4);  \
  b ^= a; b -= rot(a,14); \
  c ^= b; c -= rot(b,24); \
}

uint32_t lookup3 (
  const void *key,
  size_t      length,
  uint32_t    initval
) {
  uint32_t  a,b,c;
  const uint8_t  *k;
  const uint32_t *data32Bit;

  data32Bit = key;
  a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval;

  while (length > 12) {
    a += *(data32Bit++);
    b += *(data32Bit++);
    c += *(data32Bit++);
    mix(a,b,c);
    length -= 12;
  }

  k = (const uint8_t *)data32Bit;
  switch (length) {
    case 12: c += ((uint32_t)k[11])<<24;
    case 11: c += ((uint32_t)k[10])<<16;
    case 10: c += ((uint32_t)k[9])<<8;
    case 9 : c += k[8];
    case 8 : b += ((uint32_t)k[7])<<24;
    case 7 : b += ((uint32_t)k[6])<<16;
    case 6 : b += ((uint32_t)k[5])<<8;
    case 5 : b += k[4];
    case 4 : a += ((uint32_t)k[3])<<24;
    case 3 : a += ((uint32_t)k[2])<<16;
    case 2 : a += ((uint32_t)k[1])<<8;
    case 1 : a += k[0];
             break;
    case 0 : return c;
  }
  final(a,b,c);
  return c;
}
unsigned int stringToHash(char *word, unsigned int hashTableSize){
  unsigned int initval;
  unsigned int hashAddress;

  initval = 12345;
  hashAddress = lookup3(word, strlen(word), initval);
  return (hashAddress%hashTableSize);
  // If hashtable is guaranteed to always have a size that is a power of 2,
  // replace the line above with the following more effective line:
  //     return (hashAddress & (hashTableSize - 1));
}