一个简单的解决方案是将dict作为已排序的\ n分隔的单词存储在磁盘上,将其加载到内存中并执行二分搜索。这里唯一的非标准部分是当你进行二分搜索时,你必须向后扫描一个单词的开头。
这是一些代码! (它假定全局wordlist
指向加载字典,并wordlist_end
这只是加载的字典结束后百分点。
// Return >0 if word > word at position p.
// Return <0 if word < word at position p.
// Return 0 if word == word at position p.
static int cmp_word_at_index(size_t p, const char *word) {
while (p > 0 && wordlist[p - 1] != '\n') {
p--;
}
while (1) {
if (wordlist[p] == '\n') {
if (*word == '\0') return 0;
else return 1;
}
if (*word == '\0') {
return -1;
}
int char0 = toupper(*word);
int char1 = toupper(wordlist[p]);
if (char0 != char1) {
return (int)char0 - (int)char1;
}
++p;
++word;
}
}
// Test if a word is in the dictionary.
int is_word(const char* word_to_find) {
size_t index_min = 0;
size_t index_max = wordlist_end - wordlist;
while (index_min < index_max - 1) {
size_t index = (index_min + index_max)/2;
int c = cmp_word_at_index(index, word_to_find);
if (c == 0) return 1; // Found word.
if (c < 0) {
index_max = index;
} else {
index_min = index;
}
}
return 0;
}
这种方法的一个巨大优势是,字典存储在人类可读的方式并且你不需要任何花哨的代码来加载它(分配一块内存并一次读取()它)
如果你想使用一个trie,你可以使用一个包和后缀压缩的表示形式,下面是Donald Knuth的学生Franklin Liang的一个链接,他在论文中写了这个技巧。
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.123.7018&rep=rep1&type=pdf
它采用了简单的文字字典代表性的存储一半,为您提供了一个线索的速度,并且可以(如文字字典表示)在磁盘上存储整个事情,在一个加载走。
它使用的技巧是将所有trie节点打包到单个数组中,并在可能的情况下将它们交错。除了像常规trie中的每个阵列位置中的新指针(以及词尾标记位)之外,您还可以存储此节点用于的字母 - 这可以让您知道该节点对于您的状态是否有效或者它来自重叠节点。阅读链接的文档以获得更全面更清晰的解释,以及将树状结构包装到此阵列中的算法。
实现所描述的后缀压缩和贪婪包装算法并不是微不足道的,但它很容易。
感谢您提供指向DAWG的指针 - 这是我的一个新DS。 – xyz 2011-06-08 13:34:54
+1对于Trie数据结构 – brainydexter 2011-06-13 17:19:50
由于OP指定的唯一要求是密钥检索,因此我没有看到为什么Trie是比哈希表更好的数据结构。哈希表比Trie表现得更好,实现起来更简单。在C++ STL的上下文中,你可以使用std :: unordered_set – minism 2013-04-26 04:42:47