使用压缩节点实现 Trie 的 Go 语言程序
Trie 是一种树形数据结构,用于高效存储和检索字符串,使其成为自动完成、字典实现和模式匹配等任务的宝贵工具。压缩节点技术通过合并节点之间的公共前缀来优化空间使用,从而产生更节省内存的 Trie。在本文中,我们将探讨使用两种方法在 Go 语言中实现带有压缩节点的 Trie,第一种方法使用映射,第二种方法使用数组。
解释
压缩 Trie 是一种 Trie 数据结构,它通过将具有单个分支的连续节点组合成一个压缩节点来节省空间。在下面的表示中,根节点 [c] 对所有分支都是相同的。在下面的结构中,“card”和“care”都表示公共前缀“car”。无需为每个字符创建单独的节点,单个压缩节点即可表示此共享前缀。
c
/ \
ar o
/ |
red n
|
d
语法
type TrieNode struct{ children map[rune]*TrieNode; isEnd bool }
TrieNode 结构体包含一个名为“children”的映射,它使用 rune(字符)作为键来存储对子节点的引用。它允许在字符和子节点之间进行高效映射,使其适用于压缩 Trie 节点。“isEnd”布尔标志用于指示单词是否在当前节点结束。
算法
创建一个名为 TrieNode 的结构体来表示 Trie 中的每个节点。每个 TrieNode 应该有一个名为“children”的映射,用于存储子节点,其键为字符,值为指向 TrieNode 的指针。
包含一个布尔变量“isEnd”来指示当前节点是否表示单词的结尾。
将空根节点初始化为 Trie 的起点。
遍历所有字符后,通过将“isEnd”设置为 true 来将最后一个节点标记为单词的结尾。
要在 Trie 中搜索单词,请从根节点开始遍历单词的字符。如果在任何时候都找不到字符的子节点,或者到达单词的结尾但“isEnd”为 false,则该单词不存在于 Trie 中。
要从 Trie 中删除单词,请按照前面所述搜索该单词。
示例 1
在这个例子中,我们将使用映射实现具有压缩节点的 Trie 数据结构。在这里,我们创建一个 Trie 数据结构,将单词插入其中,并执行搜索操作以检查 Trie 中是否存在特定单词。这种方法可以节省内存并减小 Trie 的整体大小。
package main
import "fmt"
type TrieNode struct {
children map[rune]*TrieNode
isEnd bool
}
type Trie struct {
root *TrieNode
}
func NewTrie() *Trie {
return &Trie{
root: &TrieNode{
children: make(map[rune]*TrieNode),
isEnd: false,
},
}
}
func (t *Trie) Insert(word string) {
node := t.root
for _, ch := range word {
if _, ok := node.children[ch]; !ok {
node.children[ch] = &TrieNode{
children: make(map[rune]*TrieNode),
isEnd: false,
}
}
node = node.children[ch]
}
node.isEnd = true
}
func (t *Trie) Search(word string) bool {
node := t.root
for _, ch := range word {
if _, ok := node.children[ch]; !ok {
return false
}
node = node.children[ch]
}
return node.isEnd
}
func main() {
trie := NewTrie()
trie.Insert("apple")
trie.Insert("app")
trie.Insert("banana")
fmt.Println("Search 'apple':", trie.Search("apple"))
fmt.Println("Search 'app':", trie.Search("app"))
fmt.Println("Search 'banana':", trie.Search("banana"))
fmt.Println("Search 'orange':", trie.Search("orange"))
}
输出
Search 'apple': true Search 'app': true Search 'banana': true Search 'orange': false
示例 2
在这个例子中,我们将使用数组实现具有压缩节点的 Trie 数据结构。在这里,我们使用压缩节点方法,但是我们使用指向 TrieNode 的数组而不是映射来表示节点的子节点。我们创建一个 Trie 数据结构,将单词插入其中,并执行搜索操作以检查 Trie 中是否存在特定单词。与基于映射的方法相比,这种方法提供了更快的访问速度和略微减少的内存开销。
package main
import "fmt"
const alphabetSize = 26
type TrieNode struct {
children [alphabetSize]*TrieNode
isEnd bool
}
type Trie struct {
root *TrieNode
}
func NewTrie() *Trie {
return &Trie{
root: &TrieNode{},
}
}
func (t *Trie) Insert(word string) {
node := t.root
for _, ch := range word {
index := ch - 'a'
if node.children[index] == nil {
node.children[index] = &TrieNode{}
}
node = node.children[index]
}
node.isEnd = true
}
func (t *Trie) Search(word string) bool {
node := t.root
for _, ch := range word {
index := ch - 'a'
if node.children[index] == nil {
return false
}
node = node.children[index]
}
return node.isEnd
}
func main() {
trie := NewTrie()
trie.Insert("apple")
trie.Insert("app")
trie.Insert("banana")
fmt.Println("Search 'apple':", trie.Search("apple"))
fmt.Println("Search 'app':", trie.Search("app"))
fmt.Println("Search 'banana':", trie.Search("banana"))
fmt.Println("Search 'orange':", trie.Search("orange"))
}
输出
Search 'apple': true Search 'app': true Search 'banana': true Search 'orange': false
现实生活中的应用
自动完成和搜索建议
带有压缩节点的 Trie 常用于搜索引擎和文本预测系统中,以提供自动完成和搜索建议功能。当用户键入时,系统会根据他们输入的前缀快速检索建议。例如,当您在 Google 中开始键入搜索查询时,它会实时建议相关的搜索词。Trie 有效地存储大量单词,其压缩节点有助于减少内存使用,同时保持自动完成建议的快速检索时间。
拼写检查和纠正
带有压缩节点的 Trie 在拼写纠正和检查应用程序中非常有用。它们可以快速识别字典中是否存在单词,并提供更正拼写错误单词的建议。例如,像 Microsoft Word 这样的文字处理软件使用类似的技术来下划线拼写错误的单词并建议更正。Trie 结构允许快速搜索和建议,而压缩节点则可以控制内存需求,从而实现高效的实时拼写检查和纠正。
结论
压缩 Trie 是一种节省空间的数据结构,它通过将公共分支合并到压缩节点中来实现。在本文中,我们研究了如何在 Go 语言中实现带有压缩节点的 Trie,我们使用了两个不同的例子,第一个例子使用映射来表示压缩节点,而第二个例子则使用数组来实现相同目的。压缩节点的独特之处在于它们能够通过合并节点之间的公共前缀来节省内存,从而产生更节省内存的 Trie。
数据结构
网络
关系数据库管理系统 (RDBMS)
操作系统
Java
iOS
HTML
CSS
Android
Python
C 语言编程
C++
C#
MongoDB
MySQL
Javascript
PHP