散列数组索引

时间:2012-05-16 17:24:37

标签: c hash

在我的C程序中,我在结构中分配了四个8位( char )变量。如果我想散列这些数字以创建将索引数组的键(代表整个结构),我该怎么办? (在程序中有很多这样的结构;因为我经常需要在符号表中搜索它们是否存在,如果我不想创建其他结构,我还不知道要使用哪种哈希算法,如果我我想进行密钥索引搜索。

我考虑过一种散列,它取四个数字,用十六进制数字转换它们,连续放入它们,然后将出现的数字转换为十进制数字。

但是我需要一些不那么“沉重”的东西......这种方法看起来太虚荣了,我认为它不适合创建数组索引。

是吗?是否有其他类型的哈希函数,如果可能的话,它还占用的内存少于32位?

4 个答案:

答案 0 :(得分:2)

一种可能性(我认为OP没有描述)将4个char值组合成一个32位整数,然后使用哈希表的大小(可能是素数)来修改它:

unsigned int combined = (c1 << 24 ) | (c2 << 16 ) | (c3 << 8 ) | (c4);
unsigned int hashval = combined % hashtablesize;

当然,它取决于4个单独字节的实际预期值,但这种类型的散列相当有效,并且通常具有良好的分布。最好使用预期的数据集测试生成的哈希值,以确保分布有点均匀。

答案 1 :(得分:2)

您可能需要查看此list of hash functions

为了实现哈希表(我认为这是你的目标),你需要一个带avalanche effect的哈希函数来避免类似输入值的太多哈希冲突。

当然,您可以使用任何函数将您的字符转换为任意整数表示,但如果此表示形式对于不同的输入没有变化,则您实际上具有链接列表的性能(想象使用其中一个其他建议表大小为256,并且没有结构在字节4上变化。你对32位哈希的关注是什么?当然你会使用hash%tablesize进行索引编制吗?

通常,您也不会使用加密哈希函数(例如md5,sha-1)。只需选择一个非加密哈希函数(例如Pearson / Jenkins哈希)。

/* jenkins hash, copied from http://en.wikipedia.org/wiki/Jenkins_hash_function */
uint32_t jenkins_one_at_a_time_hash(char *key, size_t len)
{
  uint32_t hash, i;
  for(hash = i = 0; i < len; ++i)
  {
    hash += key[i];
    hash += (hash << 10);
    hash ^= (hash >> 6);
  }
  hash += (hash << 3);
  hash ^= (hash >> 11);
  hash += (hash << 15);
  return hash;
}

附注:当您具有良好的哈希值分布时,还要确保哈希表的大小足够大。随着阵列的占用率(负载系数)接近1,您将观察到性能下降,因为哈希冲突的可能性会增加。

答案 2 :(得分:0)

为什么不将结构放在数组中?

#include <stdio.h>

typedef struct {
  char a,b,c,d;
} item;
item items[20];

int main(int argc, char *argv[])
{
  items[0].a = 4;
  items[0].b = 6;
  items[0].c = 1;
  items[0].d = 3;
  // ...
  items[4].a = 12;
  // ...
  printf("%d %d %d %d\n", items[0].a, items[0].b, items[0].c, items[0].d);
  return 0;
}

显然,这是内存占用较少的解决方案,因为数据直接存储在主阵列中,因此不需要散列索引,因为阵列的索引可以完成作业而不占用内存。

当然你可以使用指针,一些C ++向量功能等。但这是最简单有效的方法。

唯一需要注意的是,你必须知道阵列的大小(你将拥有多少项)或者最多不会超过XXX的......

答案 3 :(得分:0)

  

是否有其他类型的哈希函数,它也占用更少的内存   超过32位,如果可能的话?

这是一个虚幻的问题。关键是数组索引 - 它不存储在任何地方,它是在查找时计算的。 C中的数组是连续的块,根据数组的开头和类型的大小乘以索引来访问单个元素。

对于密钥,只需将值转换为无符号32位类型(不要只使用intunsigned int,因为大小不一定是32位):

#include <inttypes.h>
char x[4] = { 'A', 'B', 'C', 'D' };
uint32_t *key = (uint32_t*)&x;        

然后根据表格大小做模数。