Trie 树

什么是 Trie 树

Trie 树,又称前缀树,字段典树,或单词查找树,是一种树形结构,也是哈希表的变种,它是一种专门处理字段串匹配的数据结构,用来解决在一组字符串集合中快速查找某个字符串的问题,主要被搜索引擎用来做文本词频的统计。

先看一下前辍树的图:

这棵前辍树根节点不存放数据,其他节点保存了 hello,her,hi,how,see,so 等关键词信息,如果查 he 前辍的单词可以很快返回 hello,her。

Trie 树的 Python 实现

一般来讲 trie 要实现这么几个方法

  • 插入一个单词 insert (word: str) -> None
  • 查找一个单词是否在 trie 中 search (word:str) -> bool
  • 查找一个前缀是否在 trie 中 startsWith (prefix:str) -> bool
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
class Trie:

def __init__(self):
"""
Initialize your data structure here.
"""
self.root = {}
self.end_of_word = '#'

def insert(self, word: str) -> None:
"""
Inserts a word into the trie.
"""
node = self.root
for char in word:
node = node.setdefault(char, {})
node[self.end_of_word] = self.end_of_word

def search(self, word: str) -> bool:
"""
Returns if the word is in the trie.
"""
node = self.root
for char in word:
if char not in node:
return False
node = node[char]
return self.end_of_word in node

def startsWith(self, prefix: str) -> bool:
"""
Returns if there is any word in the trie that starts with the given prefix.
"""
node = self.root
for char in prefix:
if char not in node:
return False
node = node[char]
return True

def get_start(self,prefix):
'''
给出一个前辍,打印出所有匹配的字符串
:param prefix:
:return:
'''
def get_key(pre,pre_node):
result = []
if pre_node.get(self.end_of_word):
result.append(pre)
for key in pre_node.keys():
if key != self.end_of_word:
result.extend(get_key(pre+key,pre_node.get(key)))
return result


if not self.startsWith(prefix):
return []
else:
node = self.root
for p in prefix:
node = node.get(p)
else:
return get_key(prefix,node)

if __name__ == "__main__":
trie = Trie()
trie.insert("Python")
trie.insert("Python 算法")
trie.insert("Python web")
trie.insert("Python web 开发")
trie.insert("Python web 开发 视频教程")
trie.insert("Python 算法 源码")
trie.insert("Perl 算法 源码")
print(trie.search("Perl"))
print(trie.search("Perl 算法 源码"))
print((trie.get_start('P')))
print((trie.get_start('Python web')))
print((trie.get_start('Python 算')))
print((trie.get_start('P')))
print((trie.get_start('Python web')))
print((trie.get_start('Python 算')))

代码运行结果如下:

1
2
3
4
5
False
True
['Python', 'Python 算法', 'Python 算法 源码', 'Python web', 'Python web 开发', 'Python web 开发 视频教程', 'Perl 算法 源码']
['Python web', 'Python web 开发', 'Python web 开发 视频教程']
['Python 算法', 'Python 算法 源码']

Trie 的时间复杂度

如果要在一组关键词中,频繁地查询某些关键词,用 Trie 树会非常高效。构建 Trie 树的过程,需要扫描所有的关键词,时间复杂度是 O(n)(n 表示所有关键词的长度和)。但是一旦构建成功之后,后续的查询操作会非常高效。

每次查询时,如果要查询的关键词长度是 k,那我们只需要最多比对 k 个节点,就能完成查询操作。跟原本那组关键词的长度和个数没有任何关系。所以说,构建好 Trie 树后,在其中查找关键词的时间复杂度是 O(k),k 表示要查找的关键词的长度。

Trie三方实现库

自己造轮子还要思考,编码,验证,但这是学习提升的最佳方式。如果急于应用没有时间造轮子,至少要学会如何使用轮子,下面的前辍树的轮子是一个日本人写的,大家可以学习应用下。

https://github.com/pytries/marisa-trie

https://marisa-trie.readthedocs.io/en/latest/tutorial.html

参考


Trie 树
http://example.com/2020/03/31/2020-03-31-Trie 树实现搜索引擎自动联想/
作者
NSX
发布于
2020年3月31日
许可协议