Trie,又叫前缀树,字典树等,通常用于保存字符串。为了正确区分拥有相同前缀的字符串,将每一个字符串的最后一个字符进行标记,记为键。在Trie中,每个节点只有一个字符,但可以被多个键使用。使用trie存储信息即保证了效率,由于所有相同前缀的单词都可以得到重复使用,因此也大大节省了内存。如:‘tea’,‘teach’,'teacher’三个单词只需要用7个节点存储。由于Trie的优良性能,在实际中得到了广泛的使用。其中搜索功能是Trie的典型使用场景,如搜索时输入字符后的自动补全功能就由Trie实现。
Trie的实现方式有多种,其中最常见的是通过哈希表实现,在python中直接使用字典即可。以下代码实现了Trie的添加,模糊查询与查询时自动提示前缀三个功能。
class Node(object):
def __init__(self):
self.children = {}
self.is_key = False
class BasicTrieSet(object):
def __init__(self):
self.root = Node()
def add(self, word):
current_node = self.root
for letter in word:
if letter not in current_node.children:
child = Node()
current_node.children[letter] = child
current_node = child
else:
current_node = current_node.children[letter]
current_node.is_key = True
def search(self, word):
if '*' in word:
return self.__fuzzy_search(word, self.root)
else:
current_node = self.root
for letter in word:
if letter not in current_node.children:
return False
else:
current_node = current_node.children[letter]
auto_complete = self.__get_prefix(word)
return current_node.is_key, auto_complete
def __get_prefix(self, word):
result = []
current_node = self.root
for letter in word:
if letter in current_node.children:
current_node = current_node.children[letter]
else:
return []
if current_node.is_key:
result.append(word)
for child in current_node.children:
child_node = current_node.children[child]
result.extend(self.__collect_help(word + child, child_node))
return result
def __collect_help(self, word, node):
result = []
if node.is_key:
result.append(word)
for child in node.children:
result.extend(self.__collect_help(word + child, node.children[child]))
return result
def __fuzzy_search(self, word, node):
if len(word) == 0:
return node.is_key
elif word[0] == '*':
for child in node.children:
child_node = node.children[child]
if self.__fuzzy_search(word[1:], child_node):
return True
return False
elif word[0] in node.children:
return self.__fuzzy_search(word[1:], node.children[word[0]])
else:
return False
trie = BasicTrieSet()
words = ['tea', 'teach', 'teacher', 'ta']
for word in words[:-1]:
trie.add(word)
for word in words:
print(trie.search(word))
严格来讲,对于一个长度为 L L L的字符串查询等操作的时间复杂度为 Θ ( L ) \Theta(L) Θ(L),但实际上 L L L一般较小,因此可以认为时间复杂度为 Θ ( 1 ) \Theta(1) Θ(1)。