填字游戏搜索的最佳数据结构

时间:2010-02-18 13:34:31

标签: algorithm indexing b-tree

我有一个大型数据库来解决填字游戏,包括一个单词和一个描述。 我的应用程序允许搜索特定长度的单词和特定位置的字符(这是通过艰难的方式完成的...仔细阅读所有单词并检查每个单词)。 加上描述搜索(如有必要)

例如找到单词_ _ A _ _ B(6个字母的单词,第三个字符A和最后一个B)

我想以这样的方式索引单词,以便搜索速度非常快。 我的第一个想法是使用平衡树结构,还有其他任何建议吗?

5 个答案:

答案 0 :(得分:9)

好的,我会提出一些奇怪的事情,但来自C++我已经使用Boost很长一段时间了,我来看MultiIndex库。

这个库的想法是创建一个集合,但有许多不同的方法来查询它。事实上,它可以建模数据库。

所以,让我们把我们的话放在一个表中,并放置必要的索引:

word                     |length|c0|c1|c2| ... |c26|
-------------------------|------|--|--|--| ... |---|
Singapour                |9     |S |i |n | ... |0  |

现在查询将如下所示:

Select word From table Where length=9 And c2='n' And c8='u';

不够容易吗?

为了获得最大效率,应该对表进行分区,并且索引(每个cX列一个)应该是分区的本地。

对于内存中的解决方案,每个长度有一个容器,包含与长度一样多的索引,每个索引是指向排序列表的哈希表(更容易合并)

这是一个python描述:

class Dictionary:
  def __init__(self, length):
    self.length = length
    self.words = set([])
    self.indexes = collections.defaultdict(set)

  def add(self, word):
    if len(word) != self.length:
      raise RuntimeException(word + ' is not ' + `self.length` + ' characters long')

    if word in self.words:
      raise RuntimeException(word + ' is already in the dictionary')

    self.words.add(word)

    for i in range(0,length):
      self.indexes[(i,word[i])].add(word)

  def search(self, list):
    """list: list of tuples (position,character)
    """
    def compare(lhs,rhs): return cmp(len(lhs),len(rhs))

    sets = [self.indexes[elem] for elem in list]
    sets.sort(compare)
    return reduce(intersection, sets)

我自愿提供length参数,以最小化哈希的大小,从而使搜索更好。此外,这些集合按长度排序,以便交叉点的计算更好:)

如果您愿意,请继续测试其他解决方案:)

答案 1 :(得分:4)

这个问题:Good algorithm and data structure for looking up words with missing letters?的开头与您提出的问题完全相同,但之后编辑的内容却变得非常不同且更容易。不过,你可以在那里找到一些想法。

简而言之,每个人都建议将整个字典加载到内存中,并根据字符长度将字词分组。从那里,你可以去许多不同的方向。你愿意消耗的内存越多,你就越快。

一个很好的建议是保留给定长度的单词列表的哈希表,该列表在给定位置具有给定的字母。您可以像这样构建它(在Python中):

# Build a whole lot of sorted word lists
wordlists = collections.defaultdict(list)
for word in sorted(all_words):
    for position, letter in enumerate(word):
        wordlists[len(word), position, letter].append(word)

现在,如果您需要一个以B结尾的6个字母的单词,您可以只询问wordlists[6, 5, 'B']并获得完整列表。当您知道多个字母时,如..A..B中所示,您可以选择最短的列表,并根据所需的模式测试每个字。我的计算机词典只有21个以B结尾的六个字母的单词,其中只有SCARAB匹配。

答案 2 :(得分:2)

由于您使用数据库,因此请创建后缀表 例如:

  Suffix          |   WordID   | SN
  ----------------+------------+----   
  StackOverflow           10      1
  tackOverflow            10      2
  ackOverflow             10      3
  ckOverflow              10      4
  kOverflow               10      5
  ...

使用该表,可以轻松获得包含特定位置特定字符的所有单词,
像这样:

SELECT WordID FROM suffixes
WHERE suffix >= 't' AND suffix < 'u' AND SN = 2

获取位置't'包含2的所有字词。

更新:如果您想节省空间并牺牲一点速度,可以使用suffix array

您可以将所有单词存储在一行(数组)中,其中包含一个分隔符,即$,并创建 一个后缀数组,它有指向chars的指针。现在,给定一个char c,您可以找到包含它的所有单词实例。不过,你必须检查它是否处于正确的位置 (通过检查距离$ s

的距离)

可能使用上述技术,搜索速度比搜索原始程序中的所有单词快x10。

更新2:我在我的一个实用程序中使用了数据库方法,例如,我需要找到诸如“ne”之类的后缀,我忘了调整(优化)它这个具体问题。

您只需将一个字符存储为后缀:

  Suffix   |   WordID   | SN
  ---------+------------+----   
  S                10      1
  t                10      2
  a                10      3
  c                10      4
  k                10      5
  ...

节省了大量空间。现在,查询变为

SELECT WordID FROM suffixes
WHERE suffix = 't' AND SN = 2

答案 3 :(得分:1)

您可以使用Suffix Tree或Trie。

答案 4 :(得分:1)

您可以将您的信息存储在某种类型(可能是三元搜索树)中。 Sedgewick和Bentley在this paper的第6节中描述了使用trie进行部分搜索的算法。你当然希望对不同长度的单词进行不同的尝试。该论文称部分搜索算法需要一个时间为O(n ^((k-s)/ k))的s字母被指定为n个k长度的单词。