Skip to main content
 首页 » 编程设计

python之如何在初始化方面改进我的 Trie 实现

2025年05月04日11think

我试图从一个巨大的单词列表中读入并以一种允许我稍后快速检索的方式存储它们。我首先想到使用 trie,我承认我的实现很天真,它基本上是嵌套的哈希表,每个键都是不同的字母。现在,向 trie 中插入一个单词需要很长时间(运行该程序需要 20 秒以上),我想知道是否有人对我可以做些什么来改进我的插入有任何想法?这不是作业。

import string 
import time 
 
class Trie: 
 
    def __init__(self): 
        self.root = TrieNode() 
 
    def insert_word(self, word): 
        current_node = self.root 
        for letter in word: 
            trie_node = current_node.get_node(letter) 
            current_node = trie_node 
 
class TrieNode: 
 
    def __init__(self): 
        self.data = {} 
 
    def get_node(self, letter): 
        if letter in self.data: 
            return self.data[letter] 
        else: 
            new_trie_node = TrieNode() 
            self.data[letter] = new_trie_node 
            return new_trie_node 
 
def main(): 
    start_time = time.time() 
    trie = Trie() 
 
    with open('/usr/share/dict/words', 'r') as dictionary: 
        word_list = dictionary.read() 
    word_list = word_list.split("\n") 
 
    for word in word_list: 
        trie.insert_word(word.lower()) 
 
    print time.time() - start_time, "seconds" 
 
 
if __name__ == "__main__": 
    main() 

请您参考如下方法:

在您考虑搜索工具是否正常工作之前,加速您的 trie 初始化是完全没有意义的。

在@unutbu 提到的代码中,你为什么认为它在搞乱 {'end':False} 和 pt['end']=True ?

这里有一些测试数据给你:

words_to_insert = ['foo', 'foobar'] 
queries_expecting_true = words_to_insert 
queries_expecting_false = "fo foe foob food foobare".split() 

还有另一个想法:除了能够确定查询词是否存在之外,您没有任何迹象表明您想要任何东西。如果这是正确的,您应该考虑针对内置的 set 对您的 DIY trie 进行基准测试。标准:加载速度(考虑从 pickle 执行此操作)、查询速度和内存使用情况。

如果您确实想要检索比 bool 更多的信息,请将 dict 替换为 set 并重新阅读此答案。

如果你确实想在输入字符串中搜索单词,那么你可以考虑@unutbu 引用的代码,修复了错误并在 find 函数中进行了一些加速(评估 len (input) 仅一次,使用 xrange 而不是 range (Python 2.x)) 和不必要的 TERMINAL: False 条目删除:

TERMINAL = None # Marks the end of a word 
 
def build(words, trie=None): # bugs fixed 
    if trie is None: 
        trie = {} 
    for word in words: 
        if not word: continue # bug fixed 
        pt = trie # bug fixed 
        for ch in word: 
            pt = pt.setdefault(ch, {}) 
        pt[TERMINAL] = True 
    return trie 
 
def find(input, trie): 
    len_input = len(input) 
    results = [] 
    for i in xrange(len_input): 
        pt = trie 
        for j in xrange(i, len_input + 1): 
            if TERMINAL in pt: 
                results.append(input[i:j]) 
            if j >= len_input or input[j] not in pt: 
                break 
            pt = pt[input[j]] 
    return results     

或者您可以查看 Danny Yoo's fast implementation的 Aho-Corasick algorithm .