一個簡單的解決方案是將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