【问题标题】:Data structure for fixed length string lookup固定长度字符串查找的数据结构
【发布时间】:2011-12-07 05:17:28
【问题描述】:

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

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

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

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

我正在考虑将其实现为前缀树。考虑到参数(唯一的,固定长度),我想知道是否有一个开箱即用的数据结构,我想不出它最适合这个......

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

【问题讨论】:

  • 字符串集合是否提前知道?如果是这样,您是否尝试过使用perfect hash function 生成器,例如gperf
  • @Adam 是的,所有可能的组合都是事先知道的。谢谢!我会调查的。你会碰巧有任何你喜欢的参考实现吗?

标签: c data-structures


【解决方案1】:

由于您提前知道所有字符串,您可以使用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) 中会出现一个非常大的表。如果你不需要做字符串比较,你可以省略那个表。

【讨论】:

  • 哎呀抱歉,我以为我不久前接受了这个,但显然我很烂。对不起。和 CMPH 一起去了。感谢您带领我走上正确的道路。 :)
【解决方案2】:

哈希表,即使有冲突,也将优于其他任何东西,您可以对其进行调整以减少冲突。

【讨论】:

    【解决方案3】:

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

    现在,如果超过一半的可能键正在使用中(如您所说,有数十万个),也许最简单的解决方案可以做到:只需构建一个数组,通过索引访问它(整数从字符串中推导出来)。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多