【问题标题】:Space-Efficient Data Structure for Storing a Word List?用于存储单词列表的节省空间的数据结构?
【发布时间】:2010-09-26 08:57:12
【问题描述】:

对于这种情况,有什么比Trie 更好的方法吗?

  • 存储约 10 万个英语单词的列表
  • 需要使用最少的内存
  • 查找需要合理,但不必快如闪电

我正在使用 Java,所以我的第一次尝试是只使用 Set。但是,我的目标是移动设备并且内存已经不足。由于许多英语单词都有共同的前缀,因此 trie 似乎是节省一些记忆的不错选择——有人知道其他好的选择吗?

编辑 - 更多信息 - 数据结构将用于两个操作

  • 回答:列表中是否有某个单词 XYZ?
  • 在 XYZ 周围生成一个字母不同的单词邻域

谢谢你的好建议

【问题讨论】:

  • 您是否假设没有网络连接?
  • @Milhous,现在我很想知道您的建议可以通过网络连接...

标签: java data-structures


【解决方案1】:

我看到的一种用于最小化拼写词典中空间的结构是将每个单词编码为:

  • 与最后一个共同的字符数(一个字节);和
  • 新的结局。

所以单词列表

HERE            would encode as    THIS
sanctimonious                      0,sanctimonious
sanction                           6,on
sanguine                           3,guine
trivial                            0,trivial

您在那里直接节省了 7 个字节 (19%),我怀疑这对于 20,000 个单词的字典来说是相似的,只是由于相邻单词(公共前缀)之间的最小距离。

例如,我在已排序的字典上运行了一个测试程序,并将旧存储空间计算为单词长度加一(用于终止符),新存储空间作为常用长度加一,不常用后缀长度加一终结者。这是该测试程序的最后一部分,表明您可以超过 50%:

zwiebacks   -> zygote      common=        old=1044662 new=469762 55.0%
zygote      -> zygotes     common=zygote  old=1044670 new=469765 55.0%
zygotes     -> zygotic     common=zygot   old=1044678 new=469769 55.0%
zygotic     -> zymase      common=zy      old=1044685 new=469775 55.0%
zymase      -> zymogenic   common=zym     old=1044695 new=469783 55.0%
zymogenic   -> zymology    common=zymo    old=1044704 new=469789 55.0%
zymology    -> zymolysis   common=zymol   old=1044714 new=469795 55.0%
zymolysis   -> zymoplastic common=zymo    old=1044726 new=469804 55.0%
zymoplastic -> zymoscope   common=zymo    old=1044736 new=469811 55.0%
zymoscope   -> zymurgy     common=zym     old=1044744 new=469817 55.0%
zymurgy     -> zyzzyva     common=zy      old=1044752 new=469824 55.0%
zyzzyva     -> zyzzyvas    common=zyzzyva old=1044761 new=469827 55.0%

为了加快查找速度,内存中有一个包含 26 个条目的表,用于保存以 a、b、c、...、z 开头的单词的起始偏移量。这些偏移处的单词总是以 0 作为第一个字节,因为它们与前一个单词没有相同的字母。

这似乎是一种 trie,但没有指针,如果树中的每个字符都有一个与之关联的 4 字节指针,这肯定会占用空间。

请注意,这是我 CP/M 时代的记忆比现在少得多的时候。

【讨论】:

  • +1 - 感谢分享一个聪明的算法。顺便说一句:那时,我的记忆力的可靠性远远超过了稀缺性.... :-)
【解决方案2】:

Patricia trie 可能更合适:

http://en.wikipedia.org/wiki/Patricia_tree

我的(模糊)记忆告诉我在一些早期的全文搜索引擎中使用过……

保罗。

【讨论】:

    【解决方案3】:

    你在做什么?如果是拼写检查,您可以使用布隆过滤器 - 请参阅 code kata

    【讨论】:

    • 我也打算推荐一个布隆过滤器,但考虑到他的目标,我认为布隆过滤器行不通。如果单词在列表中,布隆过滤器不会给出明确的是/否回答,并且不允许生成邻域。
    • 如果列表中的单词不是,布隆过滤器回答明确的否定。是的,邻居要求是后来添加的:)
    【解决方案4】:

    您仍然必须使用 Trie 维护树结构本身。 Huffman encoding 字母表或 N 字母(对于“tion”、“un”、“ing”等常见形式)可以利用字典中的出现频率并将条目压缩为位。

    【讨论】:

      【解决方案5】:

      完全疯狂的想法......(即很可能非常错误)

      如何将单词存储为所有可能的字母组合的树?

      那么每个“单词”只需要一个字符和两个指针(一个指向字符,一个指向终止符)。这样,它们共有的字母越多,每个单词的成本就越低。

            . .
           / /
          r-p-s-.
         /\\
        a  \s-.
       /    t-.
      c      \
              s-.
      

      汽车 鲤鱼 鲤鱼 汽车 大车 购物车

      所以对于 9 个字符和 14 个指针,我们得到 6 个“单词”,总共 25 个字母。

      搜索会很快(指针查找而不是字符比较),您可以进行一些词干优化以节省更多空间...?

      编辑:看起来我重新发明了轮子。 ;-)

      【讨论】:

        【解决方案6】:

        与保罗的帖子相关:

        您有什么理由不能在您的案例中考虑使用 Trie?如果这只是一个实现问题,这里是 Patricia trie 在 C 中插入和搜索的紧密实现(来自 NIST):

        Patricia Insert in C

        Patricia Search in C

        【讨论】:

          猜你喜欢
          • 2016-02-14
          • 1970-01-01
          • 2012-04-02
          • 1970-01-01
          • 1970-01-01
          • 2015-07-26
          • 1970-01-01
          • 2012-10-08
          • 2013-08-18
          相关资源
          最近更新 更多