我正在尝试为文字游戏解算器构建数据结构。
我需要存储约150,000套{A,A,D,E,I,L,P,T,V,Y}形式。 (它们是标准化的英文单词,即排序的字符。请注意,这是一个 multiset ,它可以包含两次相同的字母。)
需要有效地获得以下类型查询的是/否答案:是否有任何具有给定子集的集合?例如,任何已知单词是否包含{D,E,I,L,L,P}集?
要求:
那里有没有适合这种需求的数据结构?这与StackOverflow上的other set matching问题略有不同,因为目标集实际上是多集的。
答案 0 :(得分:3)
这让我想起了我做过一次的变异前缀树/特里。略有不同但它可能会奏效。如果您有大/没有边界或者您无法将其转换为您的语言(我用c ++编写代码),它可能无效。
所以基本上,在一个特里,你通常会存储与下一个字母相对应的孩子,但我所做的是我存储了与每个字母的频率相对应的子项。
问题基本上是(从我的观点来看)是,“是否有任何集合的字母与子集相同或更多?”例如,如果子集是{A,D,E,E},则需要查找是否存在至少有一个A,一个D和两个E的集合。
所以,对于特里,你有类似的东西
Root
/ | \
/ /|\ \
/ / | \ \
1 2 ... MAX <-- This represents the frequency of "A"
/|\ ..... /|\
1..MAX 1..MAX <-- Frequency of "B"
...............
...............
...............
1 ... ... ... MAX <-- Frequency of "Y"
/|\ .... .... / | \
1..MAX ...... 1 .. MAX <-- Frequency of "Z"
基本上所有的...代表了许多需要很长时间才能展示的东西。 /,|和\表示父子关系,MAX表示字母的最大频率
所以你做的是,你有一个类似的结构(我在c ++中的代码):
struct NODE {
NODE *child[MAX + 1]; // Pointers to other NODE's that represents
// the frequency of the next letter
};
创建节点时,需要将其所有子节点初始化为NULL。您可以通过构造函数(在c ++中)或makeNode()函数(如
)来完成此操作NODE* makeNode() {
NODE* n = new NODE; // Create a NODE
for(int i = 0;i <= MAX;i++) // For each child
n->child[i] = NULL; // Initialize to NULL
};
一开始,trie只是一个根
NODE* root = new NODE;
当你为trie添加一个集合时,你会得到每个字母的频率并通过trie。如果在特定节点处,与下一个字母对应的子节点为NULL,则只需创建一个新的NODE。
搜索特里结构时,搜索每个节点中与子集中字母或更大字母的频率相对应的所有子节点。例如,如果子集有3个A,则搜索所有root-&gt; child [3]然后root-&gt; child [4]然后...然后root-&gt; child [MAX]。
这可能过于复杂和令人困惑所以1)如果你认为我没有生气那么请评论什么是令人困惑的2)你可能/可能想要找到一个更简单的方法
答案 1 :(得分:2)
答案 2 :(得分:0)
您可以使用trie并将每个集合插入到trie中,使用目标子集迭代遍历trie,以查明是否有匹配的子集。至少我认为我会这样做。
'trie'实际上是为一个可执行的数据结构构思的,它非常像普通的树,但是具有不同排列的节点,例如:
A
/ \
AT AN
/ | \
| | AND
ANN ANY
|
ANNA
在上面的例子中,您可以看到这可能对您的情况有用,因为ANN和ANNA可以像集合一样被检索。您可能希望使用一些排列代码以及此类型的ADT(抽象数据类型)。
查找更多here