固定长度字符串查找的数据结构

时间:2011-10-13 18:48:08

标签: c data-structures

我有一堆字符串作为键。有点像...

AAAA ABBA ACEA ALFG
...
...
ZURF [AAA _JFS aKDJ

它们都是任意4个字符的唯一组合,并且长度都相同。有成千上万的这些。我想执行查找并检索与每个字符串关联的值。

我目前将它实现为哈希表,但主要关注的是冲突(我已经在Wiki上实现了所有策略)。

我正在考虑将其作为前缀树来实现。鉴于参数虽然(唯一,固定长度),我想知道是否有一个现成的数据结构,我想不到最适合这个......

编辑:此外,所有可能的组合都由数据文件填充一次。然后,查找以线速发生。

3 个答案:

答案 0 :(得分:6)

由于您提前知道所有字符串,因此可以使用gperf生成perfect hash function,它没有任何冲突。例如,使用四个输入字符串AAAA ABBA ACEA ALFG,它生成以下哈希函数(使用命令行gperf -L ANSI-C input.txt):

static unsigned int
hash (register const char *str, register unsigned int len)
{
  static unsigned char asso_values[] =
    {
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12,  7,  2,  5, 12, 12,
      12, 12, 12, 12, 12, 12,  0, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
      12, 12, 12, 12, 12, 12
    };
  return len + asso_values[(unsigned char)str[1]];
}

const char *
in_word_set (register const char *str, register unsigned int len)
{
  static const char * wordlist[] =
    {
      "", "", "", "",
      "ALFG",
      "",
      "ABBA",
      "", "",
      "ACEA",
      "",
      "AAAA"
    };

  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
    {
      register int key = hash (str, len);

      if (key <= MAX_HASH_VALUE && key >= 0)
        {
          register const char *s = wordlist[key];

          if (*str == *s && !strcmp (str + 1, s + 1))
            return s;
        }
    }
  return 0;
}

这需要单个表查找,长度比较和字符串比较。如果您确定您正在散列的单词是您的源词之一,那么您可以跳过字符串比较。

将输入大小从4扩展到10000个随机生成的字符串会将散列函数增加到4个表查找以及长度比较和字符串比较。但是,由于字符串比较必须将每个源字符串存储在其中,因此这将出现在编译对象文件中的一个非常大的表中(1.4 MB)。如果您不需要进行字符串比较,则可以省略该表。

答案 1 :(得分:1)

哈希表,即使有冲突,也会胜过其他任何东西,你可以调整它以减少冲突。

答案 2 :(得分:0)

首先,将每个字符串转换为整数。如果您的字母表包含64个符号(例如),则可以使用4 * 6 = 24位整数作为键。

现在,如果超过一半的可能密钥正在使用中(正如你所说,有数十万个这样的密钥),也许最简单的解决方案就是:只需构建一个数组,按索引访问它(整数从字符串推断出来。)

如果可能,请使用单个内存分配来实现此功能。它甚至可以节省内存(由于100,000次小额分配而浪费了内存)。