什么是 Trie 字典树
Trie,又称前缀树或字典树,是一种树形数据结构,它是一种专门处理字符串匹配的数据结构,用来解决在一组字符串集合中快速查找某个字符串的问题。
基本性质
Trie 树的核心思想是空间换时间,它通过利用字符串的公共前缀来减少查询时间的开销以达到提高效率的目的。
Trie 树的基本性质如下:
- 根节点不包含字符,除根节点外的每一个节点都只包含一个字符。
- 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
- 每个节点的所有子节点包含的字符都不相同。
代码实现
Trie 树的实现需要一个 TrieNode 结构体,其中包含一个布尔变量 isEnd
用于标记该节点是否是一个单词的结尾,以及一个 map children
,用于存储所有可能的下一个字符。
以下是 TrieNode 结构体的示例代码:
type TrieNode struct {
isEnd bool
children map[string]*TrieNode
}
func NewTrieNode() *TrieNode {
return &TrieNode{
isEnd: false,
children: make(map[string]*TrieNode),
}
}
Trie 树的实现需要一个 Trie 结构体,其中包含插入、查找、以及删除等操作。以下是 Trie 结构体的示例代码:
type Trie struct {
root *TrieNode
}
func NewTrie() *Trie {
return &Trie{
root: NewTrieNode(),
}
}
// Insert 插入单词
func (t *Trie) Insert(word string) {
node := t.root
for _, c := range word {
if node.children[string(c)] == nil {
node.children[string(c)] = NewTrieNode()
}
node = node.children[string(c)]
}
node.isEnd = true
}
// Search 查找单词
func (t *Trie) Search(word string) bool {
node := t.root
for _, c := range word {
if node.children[string(c)] == nil {
return false
}
node = node.children[string(c)]
}
return node.isEnd
}
// Remove 删除单词
func (t *Trie) Remove(word string) bool {
node := t.root
for _, c := range word {
if node.children[string(c)] == nil {
return false
}
node = node.children[string(c)]
}
if !node.isEnd {
return false
}
node.isEnd = false
return true
}
Insert()
方法用于插入单词,它遍历单词的每个字符,如果在当前节点的 children 中不存在该字符的节点,则创建一个新的节点。然后将节点移动到该字符的节点上,并标记最后一个节点为单词的结尾。Search()
方法用于查找单词,它遍历单词的每个字符,如果在当前节点的children
中不存在该字符的节点,则返回 false。否则,将节点移动到该字符的节点上,并返回最后一个节点是否是单词的结尾。Remove()
方法用于删除单词,它遍历单词的每个字符,如果在当前节点的 children 中不存在该字符的节点,则返回 false。否则,将节点移动到该字符的节点上,并将最后一个节点的 isEnd 标记为 false,表示不再是单词的结尾。
应用场景
1. 字符串检索、字符串自动补全
Trie 树通常用于字符串检索、字符串自动补全等场景。它可以快速地在大量的字符串中查找指定的字符串,而且查找操作的时间复杂度与字符串长度无关,只与字典中字符串的数量有关。
2. 搜索引擎关键词检索
在搜索引擎中,对于大量关键词的检索,使用 Trie 树可以大大提高搜索效率。
3. 文本编辑器输入自动补全
在文本编辑器等应用中,使用 Trie 树可以实现输入自动补全的功能,提高用户输入效率。
4.网络路由
Trie 树可以应用于网络路由中,实现高效的 IP 匹配。在路由器中,每个数据包都需要进行 IP 地址匹配,以确定其应该被路由到哪个下一个节点。使用 Trie 树可以将 IP 地址映射到树形结构上,每个节点代表一段 IP 地址的前缀,从而实现高效的 IP 匹配。具体实现方法是将每个 IP 地址转换为二进制数,然后按位插入 Trie 树中。在匹配时,从根节点开始,按照 IP 地址的二进制数逐位匹配,直到找到最长匹配的前缀。这个前缀所对应的节点就是应该路由到的下一个节点。
Trie 优缺点
优点:
- 查询字符串集合中是否包含某个字符串的效率高;
- 在多模匹配问题中,Trie 树可以被用于高效地匹配多个字符串。
缺点:
- 空间占用较高,对于大量的字符串可能会消耗过多的内存;
- 不适用于通用的关联数组,只能用于字符串集合的检索;
Trie 树如何优化
Trie 树可以被优化为压缩字典树(Compressed Trie)或者三分搜索树(Ternary Search Tree),以减少空间的占用。