字典树(Trie)是一种用于快速检索字符串的树形数据结构。它广泛应用于自动补全、拼写检查、IP路由(最长前缀匹配)、T9输入法等领域。
1. 什么是字典树(Trie)?
字典树是一种树形结构,用于存储字符串。每个节点代表一个字符串中的字符,路径从根节点到某一节点代表一个字符串。以下是一个简单的例子:
在这个例子中,插入了三个单词:"cat", "car", "dog"。我们可以看到相同前缀的单词共享了相同的路径。
2. 字典树的结构
字典树的每个节点包含以下几部分:
- 子节点:节点的子节点可以是字母表中的任何字符。
- 是否为单词结束标志:一个布尔值,表示是否为一个单词的结尾。
示例结构
考虑插入单词 "cat" 和 "car" 后的字典树:
(root)
/ \
c d
/ \
a o
/ \ \
t r g
\
e
3. 操作字典树
插入单词
插入单词时,从根节点开始,依次插入每个字符。如果字符路径不存在,则创建新的节点。最后,将最后一个字符节点标记为单词的结束。
示例:插入 "cat" 和 "car"
- 插入 "cat":
(root)
|
c
|
a
|
t (end)
- 插入 "car":
(root)
|
c
|
a
/ \
t r (end)
(end)
查找单词
查找单词时,从根节点开始,依次检查每个字符节点是否存在。如果能找到所有字符并且最后一个字符节点标记为单词的结束,则单词存在。
示例:查找 "car"
- 从根节点出发,依次检查 c -> a -> r,最后一个字符节点标记为单词的结束,返回 True。
删除单词
删除单词时,从根节点开始,依次查找每个字符节点。如果能找到所有字符且最后一个字符节点标记为单词的结束,则可以删除该单词。删除时需要注意是否需要删除路径上的中间节点。
示例:删除 "car"
- 从根节点出发,依次找到 c -> a -> r。
- 取消 r 的结束标志。如果 r 没有子节点,则删除 r,并依次检查并删除无用的中间节点 a -> c。
(root)
|
c
|
a
|
t (end)
4. 示例代码
以下是 js 实现字典树的基本操作的代码示例:
// 定义一个TrieNode类来表示字典树的节点
class TrieNode {
constructor() {
this.children = {}; // 存储子节点
this.isEndOfWord = false; // 标记是否为单词的结束
}
}
// 定义Trie类来表示字典树
class Trie {
constructor() {
this.root = new TrieNode(); // 初始化字典树的根节点
}
// 插入单词的方法
insert(word) {
let node = this.root; // 从根节点开始
for (let char of word) { // 遍历单词中的每个字符
if (!node.children[char]) { // 如果当前字符的子节点不存在
node.children[char] = new TrieNode(); // 创建一个新的TrieNode
}
node = node.children[char]; // 移动到子节点
}
node.isEndOfWord = true; // 标记单词的结束
}
// 查找单词的方法
search(word) {
let node = this.root; // 从根节点开始
for (let char of word) { // 遍历单词中的每个字符
if (!node.children[char]) { // 如果当前字符的子节点不存在
return false; // 单词不存在
}
node = node.children[char]; // 移动到子节点
}
return node.isEndOfWord; // 返回是否为单词的结束
}
// 删除单词的方法
delete(word) {
const _delete = (node, word, depth) => {
if (!node) { // 如果节点不存在
return false;
}
if (depth === word.length) { // 如果达到单词的末尾
if (!node.isEndOfWord) { // 如果当前节点不是单词的结束
return false;
}
node.isEndOfWord = false; // 取消单词结束标志
return Object.keys(node.children).length === 0; // 检查是否需要删除当前节点
}
const char = word[depth]; // 获取当前字符
if (!_delete(node.children[char], word, depth + 1)) { // 递归删除子节点
return false;
}
delete node.children[char]; // 删除子节点
return Object.keys(node.children).length === 0; // 检查当前节点是否还有其他子节点
};
_delete(this.root, word, 0); // 从根节点开始删除单词
}
}
使用示例
const trie = new Trie(); // 创建一个新的字典树实例
trie.insert("cat"); // 插入单词 "cat"
trie.insert("car"); // 插入单词 "car"
trie.insert("dog"); // 插入单词 "dog"
console.log(trie.search("cat")); // true,找到单词 "cat"
console.log(trie.search("car")); // true,找到单词 "car"
console.log(trie.search("cow")); // false,未找到单词 "cow"
trie.delete("car"); // 删除单词 "car"
console.log(trie.search("car")); // false,单词 "car" 已被删除
结语
字典树(Trie)是一种强大的数据结构,适用于各种需要快速字符串检索的应用场景。通过这篇指南,你应该能够理解并实现基本的字典树操作。希望这篇博客对你有所帮助!