3-9 Trie(前缀树,26进制树)
Trie(前缀树 / Prefix Tree)
Trie(前缀树,Prefix Tree),又称字典树(Digital Tree),是一种专门用于处理字符串集合的树形数据结构。它的核心思想是:利用字符串的公共前缀来节省存储空间并加速查询。
在 Trie 中,每个节点代表一个字符(Character),从根节点(Root)到某个节点的路径代表一个字符串前缀。如果一条从根到某节点的路径对应一个完整的单词,则该节点会被标记为单词结尾(End of Word)。对于只包含小写英文字母的 Trie,每个节点最多有 26 个子节点,因此它是一棵 26 叉树(26-ary Tree)。
下面是一棵包含 "cat", "car", "care", "dog", "do" 五个单词的 Trie:
(root)
/ \
c d
| |
a o [E]
/ \ |
t r [E] g
[E] | [E]
e
[E]
其中 [E] 表示该节点是一个单词的结尾。可以看到 "car" 和 "care" 共享前缀 "car","do" 和 "dog" 共享前缀 "do"——这正是 Trie 的优势所在。
节点定义
Trie 的节点需要两部分信息:指向子节点的指针数组,以及一个标记该节点是否为单词结尾的布尔值。
C++ 节点定义
struct TrieNode {
TrieNode* children[26]; // 26 letters: a-z
bool isEndOfWord; // true if node represents end of a word
TrieNode() {
for (int i = 0; i < 26; i++)
children[i] = nullptr;
isEndOfWord = false;
}
};
C++ 使用 struct 配合构造函数初始化,children 数组固定 26 个槽位对应 a-z,初始全部为 nullptr。
C 节点定义
#include <stdbool.h>
typedef struct TrieNode {
struct TrieNode* children[26]; // 26 letters: a-z
bool isEndOfWord; // true if node represents end of a word
} TrieNode;
// Create and initialize a new Trie node
TrieNode* createNode() {
TrieNode* node = (TrieNode*)malloc(sizeof(TrieNode));
for (int i = 0; i < 26; i++)
node->children[i] = NULL;
node->isEndOfWord = false;
return node;
}
C 语言使用 typedef 定义结构体,并通过 malloc 动态分配内存。createNode 函数负责初始化所有字段。
Python 节点定义
class TrieNode:
def __init__(self):
self.children = {} # dict: char -> TrieNode
self.is_end_of_word = False
Python 版本使用字典(dict)存储子节点,键为字符,值为子节点引用。这种方式更加灵活,不需要预先分配固定大小的数组,且天然支持任意字符集。
Go 节点定义
type TrieNode struct {
children [26]*TrieNode // 26 letters: a-z
isEnd bool // true if node represents end of a word
}
Go 语言使用结构体 TrieNode 定义节点,children 是固定长度为 26 的数组,对应 a-z 共 26 个小写字母。Go 中数组会自动初始化为零值(指针为 nil,布尔值为 false),因此无需显式初始化。
插入操作
插入(Insert)的核心思路是:从根节点出发,逐个处理字符串中的字符。如果对应字符的子节点已存在则沿其继续,否则创建新节点。处理完最后一个字符后,将当前节点标记为单词结尾。
例如,依次插入 "cat", "car", "care", "dog", "do":
- 插入
"cat":创建 c -> a -> t 路径,标记 t 为单词结尾 - 插入
"car":复用 c -> a,从 a 创建新子节点 r,标记 r 为单词结尾 - 插入
"care":复用 c -> a -> r,从 r 创建新子节点 e,标记 e 为单词结尾 - 插入
"dog":创建 d -> o -> g 路径,标记 g 为单词结尾 - 插入
"do":复用 d -> o,标记 o 为单词结尾
C++ 插入实现
#include <iostream>
#include <string>
using namespace std;
struct TrieNode {
TrieNode* children[26];
bool isEndOfWord;
TrieNode() {
for (int i = 0; i < 26; i++)
children[i] = nullptr;
isEndOfWord = false;
}
};
void insert(TrieNode* root, const string& word) {
TrieNode* curr = root;
for (char ch : word) {
int index = ch - 'a'; // map character to 0-25
if (curr->children[index] == nullptr)
curr->children[index] = new TrieNode();
curr = curr->children[index];
}
curr->isEndOfWord = true; // mark last node as end of word
}
int main() {
TrieNode* root = new TrieNode();
insert(root, "cat");
insert(root, "car");
insert(root, "care");
insert(root, "dog");
insert(root, "do");
cout << "Words inserted: cat, car, care, dog, do" << endl;
return 0;
}
C 插入实现
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef struct TrieNode {
struct TrieNode* children[26];
bool isEndOfWord;
} TrieNode;
TrieNode* createNode() {
TrieNode* node = (TrieNode*)malloc(sizeof(TrieNode));
for (int i = 0; i < 26; i++)
node->children[i] = NULL;
node->isEndOfWord = false;
return node;
}
void insert(TrieNode* root, const char* word) {
TrieNode* curr = root;
for (int i = 0; word[i] != '\0'; i++) {
int index = word[i] - 'a'; // map character to 0-25
if (curr->children[index] == NULL)
curr->children[index] = createNode();
curr = curr->children[index];
}
curr->isEndOfWord = true; // mark last node as end of word
}
int main() {
TrieNode* root = createNode();
insert(root, "cat");
insert(root, "car");
insert(root, "care");
insert(root, "dog");
insert(root, "do");
printf("Words inserted: cat, car, care, dog, do\n");
return 0;
}
Python 插入实现
class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False
def insert(root, word):
curr = root
for ch in word:
if ch not in curr.children:
curr.children[ch] = TrieNode()
curr = curr.children[ch]
curr.is_end_of_word = True # mark last node as end of word
if __name__ == '__main__':
root = TrieNode()
insert(root, "cat")
insert(root, "car")
insert(root, "care")
insert(root, "dog")
insert(root, "do")
print("Words inserted: cat, car, care, dog, do")
运行该程序将输出:
Words inserted: cat, car, care, dog, do
Go 插入实现
package main
import "fmt"
type TrieNode struct {
children [26]*TrieNode
isEnd bool
}
func insert(root *TrieNode, word string) {
curr := root
for _, ch := range word {
index := ch - 'a' // map character to 0-25
if curr.children[index] == nil {
curr.children[index] = &TrieNode{}
}
curr = curr.children[index]
}
curr.isEnd = true // mark last node as end of word
}
func main() {
root := &TrieNode{}
insert(root, "cat")
insert(root, "car")
insert(root, "care")
insert(root, "dog")
insert(root, "do")
fmt.Println("Words inserted: cat, car, care, dog, do")
}
运行该程序将输出:
Words inserted: cat, car, care, dog, do
插入操作的时间复杂度为 O(m),其中 m 为待插入字符串的长度。每次插入最多创建 m 个新节点。
搜索操作
搜索(Search)用于判断一个完整的单词是否存在于 Trie 中。从根节点出发,逐个字符向下查找。如果某个字符对应的子节点不存在,说明该单词不在 Trie 中;如果顺利遍历完所有字符,还需要检查最后到达的节点是否被标记为单词结尾。
C++ 搜索实现
#include <iostream>
#include <string>
using namespace std;
struct TrieNode {
TrieNode* children[26];
bool isEndOfWord;
TrieNode() {
for (int i = 0; i < 26; i++) children[i] = nullptr;
isEndOfWord = false;
}
};
void insert(TrieNode* root, const string& word) {
TrieNode* curr = root;
for (char ch : word) {
int index = ch - 'a';
if (curr->children[index] == nullptr)
curr->children[index] = new TrieNode();
curr = curr->children[index];
}
curr->isEndOfWord = true;
}
// Search for a complete word in the Trie
bool search(TrieNode* root, const string& word) {
TrieNode* curr = root;
for (char ch : word) {
int index = ch - 'a';
if (curr->children[index] == nullptr)
return false; // character path not found
curr = curr->children[index];
}
return curr->isEndOfWord; // true only if it's a complete word
}
int main() {
TrieNode* root = new TrieNode();
insert(root, "cat");
insert(root, "car");
insert(root, "care");
insert(root, "dog");
insert(root, "do");
cout << "Search 'cat': " << (search(root, "cat") ? "Found" : "Not found") << endl;
cout << "Search 'ca': " << (search(root, "ca") ? "Found" : "Not found") << endl;
cout << "Search 'cow': " << (search(root, "cow") ? "Found" : "Not found") << endl;
return 0;
}
C 搜索实现
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct TrieNode {
struct TrieNode* children[26];
bool isEndOfWord;
} TrieNode;
TrieNode* createNode() {
TrieNode* node = (TrieNode*)malloc(sizeof(TrieNode));
for (int i = 0; i < 26; i++) node->children[i] = NULL;
node->isEndOfWord = false;
return node;
}
void insert(TrieNode* root, const char* word) {
TrieNode* curr = root;
for (int i = 0; word[i] != '\0'; i++) {
int index = word[i] - 'a';
if (curr->children[index] == NULL)
curr->children[index] = createNode();
curr = curr->children[index];
}
curr->isEndOfWord = true;
}
// Search for a complete word in the Trie
bool search(TrieNode* root, const char* word) {
TrieNode* curr = root;
for (int i = 0; word[i] != '\0'; i++) {
int index = word[i] - 'a';
if (curr->children[index] == NULL)
return false; // character path not found
curr = curr->children[index];
}
return curr->isEndOfWord; // true only if it's a complete word
}
int main() {
TrieNode* root = createNode();
insert(root, "cat");
insert(root, "car");
insert(root, "care");
insert(root, "dog");
insert(root, "do");
printf("Search 'cat': %s\n", search(root, "cat") ? "Found" : "Not found");
printf("Search 'ca': %s\n", search(root, "ca") ? "Found" : "Not found");
printf("Search 'cow': %s\n", search(root, "cow") ? "Found" : "Not found");
return 0;
}
Python 搜索实现
class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False
def insert(root, word):
curr = root
for ch in word:
if ch not in curr.children:
curr.children[ch] = TrieNode()
curr = curr.children[ch]
curr.is_end_of_word = True
# Search for a complete word in the Trie
def search(root, word):
curr = root
for ch in word:
if ch not in curr.children:
return False # character path not found
curr = curr.children[ch]
return curr.is_end_of_word # true only if it's a complete word
if __name__ == '__main__':
root = TrieNode()
for w in ["cat", "car", "care", "dog", "do"]:
insert(root, w)
print(f"Search 'cat': {'Found' if search(root, 'cat') else 'Not found'}")
print(f"Search 'ca': {'Found' if search(root, 'ca') else 'Not found'}")
print(f"Search 'cow': {'Found' if search(root, 'cow') else 'Not found'}")
运行该程序将输出:
Search 'cat': Found
Search 'ca': Not found
Search 'cow': Not found
"cat"被找到,因为 Trie 中存在完整的"cat"路径且 t 节点被标记为单词结尾"ca"未找到,虽然路径 c -> a 存在,但 a 节点未被标记为单词结尾——"ca"只是一个前缀,不是完整单词"cow"未找到,因为从节点 a 无法沿 'w' 继续向下
Go 搜索实现
package main
import "fmt"
type TrieNode struct {
children [26]*TrieNode
isEnd bool
}
func insert(root *TrieNode, word string) {
curr := root
for _, ch := range word {
index := ch - 'a'
if curr.children[index] == nil {
curr.children[index] = &TrieNode{}
}
curr = curr.children[index]
}
curr.isEnd = true
}
// Search for a complete word in the Trie
func search(root *TrieNode, word string) bool {
curr := root
for _, ch := range word {
index := ch - 'a'
if curr.children[index] == nil {
return false // character path not found
}
curr = curr.children[index]
}
return curr.isEnd // true only if it's a complete word
}
func main() {
root := &TrieNode{}
insert(root, "cat")
insert(root, "car")
insert(root, "care")
insert(root, "dog")
insert(root, "do")
fmt.Printf("Search 'cat': %s\n", foundStr(search(root, "cat")))
fmt.Printf("Search 'ca': %s\n", foundStr(search(root, "ca")))
fmt.Printf("Search 'cow': %s\n", foundStr(search(root, "cow")))
}
func foundStr(found bool) string {
if found {
return "Found"
}
return "Not found"
}
运行该程序将输出:
Search 'cat': Found
Search 'ca': Not found
Search 'cow': Not found
前缀搜索(StartsWith)
前缀搜索(Prefix Search)与普通搜索类似,但不要求到达的节点是单词结尾。只需判断 Trie 中是否存在以给定前缀开头的单词即可。这在自动补全(Autocomplete)等场景中非常有用。
C++ 前缀搜索实现
#include <iostream>
#include <string>
using namespace std;
struct TrieNode {
TrieNode* children[26];
bool isEndOfWord;
TrieNode() {
for (int i = 0; i < 26; i++) children[i] = nullptr;
isEndOfWord = false;
}
};
void insert(TrieNode* root, const string& word) {
TrieNode* curr = root;
for (char ch : word) {
int index = ch - 'a';
if (curr->children[index] == nullptr)
curr->children[index] = new TrieNode();
curr = curr->children[index];
}
curr->isEndOfWord = true;
}
// Check if any word in the Trie starts with the given prefix
bool startsWith(TrieNode* root, const string& prefix) {
TrieNode* curr = root;
for (char ch : prefix) {
int index = ch - 'a';
if (curr->children[index] == nullptr)
return false; // prefix path not found
curr = curr->children[index];
}
return true; // prefix exists, regardless of isEndOfWord
}
int main() {
TrieNode* root = new TrieNode();
insert(root, "cat");
insert(root, "car");
insert(root, "care");
insert(root, "dog");
insert(root, "do");
cout << "StartsWith 'ca': " << (startsWith(root, "ca") ? "Yes" : "No") << endl;
cout << "StartsWith 'do': " << (startsWith(root, "do") ? "Yes" : "No") << endl;
cout << "StartsWith 'ba': " << (startsWith(root, "ba") ? "Yes" : "No") << endl;
cout << "StartsWith 'catx': " << (startsWith(root, "catx") ? "Yes" : "No") << endl;
return 0;
}
C 前缀搜索实现
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct TrieNode {
struct TrieNode* children[26];
bool isEndOfWord;
} TrieNode;
TrieNode* createNode() {
TrieNode* node = (TrieNode*)malloc(sizeof(TrieNode));
for (int i = 0; i < 26; i++) node->children[i] = NULL;
node->isEndOfWord = false;
return node;
}
void insert(TrieNode* root, const char* word) {
TrieNode* curr = root;
for (int i = 0; word[i] != '\0'; i++) {
int index = word[i] - 'a';
if (curr->children[index] == NULL)
curr->children[index] = createNode();
curr = curr->children[index];
}
curr->isEndOfWord = true;
}
// Check if any word in the Trie starts with the given prefix
bool startsWith(TrieNode* root, const char* prefix) {
TrieNode* curr = root;
for (int i = 0; prefix[i] != '\0'; i++) {
int index = prefix[i] - 'a';
if (curr->children[index] == NULL)
return false; // prefix path not found
curr = curr->children[index];
}
return true; // prefix exists, regardless of isEndOfWord
}
int main() {
TrieNode* root = createNode();
insert(root, "cat");
insert(root, "car");
insert(root, "care");
insert(root, "dog");
insert(root, "do");
printf("StartsWith 'ca': %s\n", startsWith(root, "ca") ? "Yes" : "No");
printf("StartsWith 'do': %s\n", startsWith(root, "do") ? "Yes" : "No");
printf("StartsWith 'ba': %s\n", startsWith(root, "ba") ? "Yes" : "No");
printf("StartsWith 'catx': %s\n", startsWith(root, "catx") ? "Yes" : "No");
return 0;
}
Python 前缀搜索实现
class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False
def insert(root, word):
curr = root
for ch in word:
if ch not in curr.children:
curr.children[ch] = TrieNode()
curr = curr.children[ch]
curr.is_end_of_word = True
# Check if any word in the Trie starts with the given prefix
def starts_with(root, prefix):
curr = root
for ch in prefix:
if ch not in curr.children:
return False # prefix path not found
curr = curr.children[ch]
return True # prefix exists, regardless of is_end_of_word
if __name__ == '__main__':
root = TrieNode()
for w in ["cat", "car", "care", "dog", "do"]:
insert(root, w)
print(f"StartsWith 'ca': {'Yes' if starts_with(root, 'ca') else 'No'}")
print(f"StartsWith 'do': {'Yes' if starts_with(root, 'do') else 'No'}")
print(f"StartsWith 'ba': {'Yes' if starts_with(root, 'ba') else 'No'}")
print(f"StartsWith 'catx': {'Yes' if starts_with(root, 'catx') else 'No'}")
运行该程序将输出:
StartsWith 'ca': Yes
StartsWith 'do': Yes
StartsWith 'ba': No
StartsWith 'catx': No
"ca"返回 Yes,因为 Trie 中有"cat","car","care"都以"ca"开头"do"返回 Yes,因为"dog"和"do"都以"do"开头"ba"返回 No,因为 Trie 中没有任何单词以"ba"开头"catx"返回 No,因为沿着 c -> a -> t 继续后,不存在 'x' 子节点
Go 前缀搜索实现
package main
import "fmt"
type TrieNode struct {
children [26]*TrieNode
isEnd bool
}
func insert(root *TrieNode, word string) {
curr := root
for _, ch := range word {
index := ch - 'a'
if curr.children[index] == nil {
curr.children[index] = &TrieNode{}
}
curr = curr.children[index]
}
curr.isEnd = true
}
// Check if any word in the Trie starts with the given prefix
func startsWith(root *TrieNode, prefix string) bool {
curr := root
for _, ch := range prefix {
index := ch - 'a'
if curr.children[index] == nil {
return false // prefix path not found
}
curr = curr.children[index]
}
return true // prefix exists, regardless of isEnd
}
func main() {
root := &TrieNode{}
insert(root, "cat")
insert(root, "car")
insert(root, "care")
insert(root, "dog")
insert(root, "do")
fmt.Printf("StartsWith 'ca': %s\n", yesNo(startsWith(root, "ca")))
fmt.Printf("StartsWith 'do': %s\n", yesNo(startsWith(root, "do")))
fmt.Printf("StartsWith 'ba': %s\n", yesNo(startsWith(root, "ba")))
fmt.Printf("StartsWith 'catx': %s\n", yesNo(startsWith(root, "catx")))
}
func yesNo(val bool) string {
if val {
return "Yes"
}
return "No"
}
运行该程序将输出:
StartsWith 'ca': Yes
StartsWith 'do': Yes
StartsWith 'ba': No
StartsWith 'catx': No
删除操作
删除(Delete)是最复杂的操作。核心原则是:只删除不属于其他单词的节点。具体规则如下:
- 如果单词不存在于 Trie 中,无需操作
- 如果被删除的单词是某个更长单词的前缀(如删除
"car"但"care"存在),只需取消标记isEndOfWord,不删除任何节点 - 如果被删除的单词的节点不与其他单词共享,则从叶子向根逐个删除无用节点,直到遇到被其他单词使用的节点
C++ 删除实现
#include <iostream>
#include <string>
using namespace std;
struct TrieNode {
TrieNode* children[26];
bool isEndOfWord;
TrieNode() {
for (int i = 0; i < 26; i++) children[i] = nullptr;
isEndOfWord = false;
}
};
void insert(TrieNode* root, const string& word) {
TrieNode* curr = root;
for (char ch : word) {
int index = ch - 'a';
if (curr->children[index] == nullptr)
curr->children[index] = new TrieNode();
curr = curr->children[index];
}
curr->isEndOfWord = true;
}
bool search(TrieNode* root, const string& word) {
TrieNode* curr = root;
for (char ch : word) {
int index = ch - 'a';
if (curr->children[index] == nullptr) return false;
curr = curr->children[index];
}
return curr->isEndOfWord;
}
// Check if a node has any children
bool isEmpty(TrieNode* node) {
for (int i = 0; i < 26; i++) {
if (node->children[i] != nullptr)
return false;
}
return true;
}
// Recursive delete: returns the node to be deleted (or nullptr)
TrieNode* deleteHelper(TrieNode* root, const string& word, int depth) {
if (root == nullptr) return nullptr;
if (depth == (int)word.size()) {
// reached the last character of the word
if (root->isEndOfWord)
root->isEndOfWord = false; // unmark end of word
// if node has no children, it can be safely deleted
if (isEmpty(root)) {
delete root;
return nullptr;
}
return root;
}
int index = word[depth] - 'a';
root->children[index] = deleteHelper(root->children[index], word, depth + 1);
// after child deletion, check if current node is now useless
if (isEmpty(root) && !root->isEndOfWord) {
delete root;
return nullptr;
}
return root;
}
void deleteWord(TrieNode*& root, const string& word) {
deleteHelper(root, word, 0);
}
int main() {
TrieNode* root = new TrieNode();
insert(root, "cat");
insert(root, "car");
insert(root, "care");
insert(root, "dog");
insert(root, "do");
cout << "Before deletion:" << endl;
cout << " Search 'car': " << (search(root, "car") ? "Found" : "Not found") << endl;
cout << " Search 'care': " << (search(root, "care") ? "Found" : "Not found") << endl;
deleteWord(root, "car");
cout << "\nAfter deleting 'car':" << endl;
cout << " Search 'car': " << (search(root, "car") ? "Found" : "Not found") << endl;
cout << " Search 'care': " << (search(root, "care") ? "Found" : "Not found") << endl;
deleteWord(root, "dog");
cout << "\nAfter deleting 'dog':" << endl;
cout << " Search 'dog': " << (search(root, "dog") ? "Found" : "Not found") << endl;
cout << " Search 'do': " << (search(root, "do") ? "Found" : "Not found") << endl;
return 0;
}
C 删除实现
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef struct TrieNode {
struct TrieNode* children[26];
bool isEndOfWord;
} TrieNode;
TrieNode* createNode() {
TrieNode* node = (TrieNode*)malloc(sizeof(TrieNode));
for (int i = 0; i < 26; i++) node->children[i] = NULL;
node->isEndOfWord = false;
return node;
}
void insert(TrieNode* root, const char* word) {
TrieNode* curr = root;
for (int i = 0; word[i] != '\0'; i++) {
int index = word[i] - 'a';
if (curr->children[index] == NULL)
curr->children[index] = createNode();
curr = curr->children[index];
}
curr->isEndOfWord = true;
}
bool search(TrieNode* root, const char* word) {
TrieNode* curr = root;
for (int i = 0; word[i] != '\0'; i++) {
int index = word[i] - 'a';
if (curr->children[index] == NULL) return false;
curr = curr->children[index];
}
return curr->isEndOfWord;
}
// Check if a node has any children
bool isEmpty(TrieNode* node) {
for (int i = 0; i < 26; i++) {
if (node->children[i] != NULL)
return false;
}
return true;
}
// Recursive delete: returns the node pointer (NULL if deleted)
TrieNode* deleteHelper(TrieNode* root, const char* word, int depth, int len) {
if (root == NULL) return NULL;
if (depth == len) {
// reached the last character of the word
if (root->isEndOfWord)
root->isEndOfWord = false; // unmark end of word
if (isEmpty(root)) {
free(root);
return NULL;
}
return root;
}
int index = word[depth] - 'a';
root->children[index] = deleteHelper(root->children[index], word, depth + 1, len);
// after child deletion, check if current node is now useless
if (isEmpty(root) && !root->isEndOfWord) {
free(root);
return NULL;
}
return root;
}
void deleteWord(TrieNode** root, const char* word) {
*root = deleteHelper(*root, word, 0, strlen(word));
}
int main() {
TrieNode* root = createNode();
insert(root, "cat");
insert(root, "car");
insert(root, "care");
insert(root, "dog");
insert(root, "do");
printf("Before deletion:\n");
printf(" Search 'car': %s\n", search(root, "car") ? "Found" : "Not found");
printf(" Search 'care': %s\n", search(root, "care") ? "Found" : "Not found");
deleteWord(&root, "car");
printf("\nAfter deleting 'car':\n");
printf(" Search 'car': %s\n", search(root, "car") ? "Found" : "Not found");
printf(" Search 'care': %s\n", search(root, "care") ? "Found" : "Not found");
deleteWord(&root, "dog");
printf("\nAfter deleting 'dog':\n");
printf(" Search 'dog': %s\n", search(root, "dog") ? "Found" : "Not found");
printf(" Search 'do': %s\n", search(root, "do") ? "Found" : "Not found");
return 0;
}
Python 删除实现
class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False
def insert(root, word):
curr = root
for ch in word:
if ch not in curr.children:
curr.children[ch] = TrieNode()
curr = curr.children[ch]
curr.is_end_of_word = True
def search(root, word):
curr = root
for ch in word:
if ch not in curr.children:
return False
curr = curr.children[ch]
return curr.is_end_of_word
def _delete_helper(node, word, depth):
if node is None:
return None
if depth == len(word):
# reached the last character of the word
if node.is_end_of_word:
node.is_end_of_word = False # unmark end of word
# if node has no children, it can be safely deleted
if not node.children:
return None
return node
ch = word[depth]
if ch in node.children:
node.children[ch] = _delete_helper(node.children[ch], word, depth + 1)
# after child deletion, check if current node is now useless
if node.children[ch] is None:
del node.children[ch]
# if node has no children and is not end of another word, delete it
if not node.children and not node.is_end_of_word:
return None
return node
def delete_word(root, word):
_delete_helper(root, word, 0)
if __name__ == '__main__':
root = TrieNode()
for w in ["cat", "car", "care", "dog", "do"]:
insert(root, w)
print("Before deletion:")
print(f" Search 'car': {'Found' if search(root, 'car') else 'Not found'}")
print(f" Search 'care': {'Found' if search(root, 'care') else 'Not found'}")
delete_word(root, "car")
print("\nAfter deleting 'car':")
print(f" Search 'car': {'Found' if search(root, 'car') else 'Not found'}")
print(f" Search 'care': {'Found' if search(root, 'care') else 'Not found'}")
delete_word(root, "dog")
print("\nAfter deleting 'dog':")
print(f" Search 'dog': {'Found' if search(root, 'dog') else 'Not found'}")
print(f" Search 'do': {'Found' if search(root, 'do') else 'Not found'}")
运行该程序将输出:
Before deletion:
Search 'car': Found
Search 'care': Found
After deleting 'car':
Search 'car': Not found
Search 'care': Found
After deleting 'dog':
Search 'dog': Not found
Search 'do': Found
- 删除
"car"后,"care"仍然存在。因为"car"是"care"的前缀,删除操作只是取消了 r 节点的isEndOfWord标记,节点本身被保留(因为 e 子节点仍在使用) - 删除
"dog"后,"do"仍然存在。g 节点被删除(因为它是叶子且不是单词结尾),但 o 节点被保留(因为它是"do"的单词结尾)
Go 删除实现
package main
import "fmt"
type TrieNode struct {
children [26]*TrieNode
isEnd bool
}
func insert(root *TrieNode, word string) {
curr := root
for _, ch := range word {
index := ch - 'a'
if curr.children[index] == nil {
curr.children[index] = &TrieNode{}
}
curr = curr.children[index]
}
curr.isEnd = true
}
func search(root *TrieNode, word string) bool {
curr := root
for _, ch := range word {
index := ch - 'a'
if curr.children[index] == nil {
return false
}
curr = curr.children[index]
}
return curr.isEnd
}
// Check if a node has any children
func isEmpty(node *TrieNode) bool {
for i := 0; i < 26; i++ {
if node.children[i] != nil {
return false
}
}
return true
}
// Recursive delete: returns the node to be kept (or nil if deleted)
func deleteHelper(root *TrieNode, word string, depth int) *TrieNode {
if root == nil {
return nil
}
if depth == len(word) {
// reached the last character of the word
if root.isEnd {
root.isEnd = false // unmark end of word
}
// if node has no children, it can be safely deleted
if isEmpty(root) {
return nil
}
return root
}
index := word[depth] - 'a'
root.children[index] = deleteHelper(root.children[index], word, depth+1)
// after child deletion, check if current node is now useless
if isEmpty(root) && !root.isEnd {
return nil
}
return root
}
func deleteWord(root *TrieNode, word string) {
deleteHelper(root, word, 0)
}
func foundStr(found bool) string {
if found {
return "Found"
}
return "Not found"
}
func main() {
root := &TrieNode{}
insert(root, "cat")
insert(root, "car")
insert(root, "care")
insert(root, "dog")
insert(root, "do")
fmt.Println("Before deletion:")
fmt.Printf(" Search 'car': %s\n", foundStr(search(root, "car")))
fmt.Printf(" Search 'care': %s\n", foundStr(search(root, "care")))
deleteWord(root, "car")
fmt.Println("\nAfter deleting 'car':")
fmt.Printf(" Search 'car': %s\n", foundStr(search(root, "car")))
fmt.Printf(" Search 'care': %s\n", foundStr(search(root, "care")))
deleteWord(root, "dog")
fmt.Println("\nAfter deleting 'dog':")
fmt.Printf(" Search 'dog': %s\n", foundStr(search(root, "dog")))
fmt.Printf(" Search 'do': %s\n", foundStr(search(root, "do")))
}
运行该程序将输出:
Before deletion:
Search 'car': Found
Search 'care': Found
After deleting 'car':
Search 'car': Not found
Search 'care': Found
After deleting 'dog':
Search 'dog': Not found
Search 'do': Found
遍历所有单词
遍历(Traverse)所有单词使用深度优先搜索(DFS, Depth-First Search)。从根节点出发,递归访问每个子节点,沿途记录当前路径对应的字符前缀。当遇到标记为单词结尾的节点时,将当前前缀作为一个完整单词输出。
C++ 遍历实现
#include <iostream>
#include <string>
using namespace std;
struct TrieNode {
TrieNode* children[26];
bool isEndOfWord;
TrieNode() {
for (int i = 0; i < 26; i++) children[i] = nullptr;
isEndOfWord = false;
}
};
void insert(TrieNode* root, const string& word) {
TrieNode* curr = root;
for (char ch : word) {
int index = ch - 'a';
if (curr->children[index] == nullptr)
curr->children[index] = new TrieNode();
curr = curr->children[index];
}
curr->isEndOfWord = true;
}
// DFS to collect all words in the Trie
void collectWords(TrieNode* node, string prefix) {
if (node->isEndOfWord) {
cout << prefix << endl; // found a complete word
}
for (int i = 0; i < 26; i++) {
if (node->children[i] != nullptr) {
char nextChar = 'a' + i;
collectWords(node->children[i], prefix + nextChar);
}
}
}
void listAllWords(TrieNode* root) {
collectWords(root, "");
}
int main() {
TrieNode* root = new TrieNode();
insert(root, "cat");
insert(root, "car");
insert(root, "care");
insert(root, "dog");
insert(root, "do");
cout << "All words in the Trie:" << endl;
listAllWords(root);
return 0;
}
C 遍历实现
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef struct TrieNode {
struct TrieNode* children[26];
bool isEndOfWord;
} TrieNode;
TrieNode* createNode() {
TrieNode* node = (TrieNode*)malloc(sizeof(TrieNode));
for (int i = 0; i < 26; i++) node->children[i] = NULL;
node->isEndOfWord = false;
return node;
}
void insert(TrieNode* root, const char* word) {
TrieNode* curr = root;
for (int i = 0; word[i] != '\0'; i++) {
int index = word[i] - 'a';
if (curr->children[index] == NULL)
curr->children[index] = createNode();
curr = curr->children[index];
}
curr->isEndOfWord = true;
}
// DFS to collect all words in the Trie
void collectWords(TrieNode* node, char* prefix, int depth) {
if (node->isEndOfWord) {
prefix[depth] = '\0';
printf("%s\n", prefix); // found a complete word
}
for (int i = 0; i < 26; i++) {
if (node->children[i] != NULL) {
prefix[depth] = 'a' + i;
collectWords(node->children[i], prefix, depth + 1);
}
}
}
void listAllWords(TrieNode* root) {
char buffer[256]; // buffer for building words
collectWords(root, buffer, 0);
}
int main() {
TrieNode* root = createNode();
insert(root, "cat");
insert(root, "car");
insert(root, "care");
insert(root, "dog");
insert(root, "do");
printf("All words in the Trie:\n");
listAllWords(root);
return 0;
}
Python 遍历实现
class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False
def insert(root, word):
curr = root
for ch in word:
if ch not in curr.children:
curr.children[ch] = TrieNode()
curr = curr.children[ch]
curr.is_end_of_word = True
# DFS to collect all words in the Trie
def collect_words(node, prefix, result):
if node.is_end_of_word:
result.append(prefix) # found a complete word
for ch, child in sorted(node.children.items()):
collect_words(child, prefix + ch, result)
def list_all_words(root):
result = []
collect_words(root, "", result)
return result
if __name__ == '__main__':
root = TrieNode()
for w in ["cat", "car", "care", "dog", "do"]:
insert(root, w)
print("All words in the Trie:")
for word in list_all_words(root):
print(word)
运行该程序将输出:
All words in the Trie:
car
care
cat
do
dog
输出按字典序排列。这是因为从 a 到 z(或按字母顺序遍历字典键)的 DFS 天然产生了字典序的结果。遍历所有单词的时间复杂度为 O(n),其中 n 为 Trie 中的总字符数(即所有节点的数量)。
Go 遍历实现
package main
import "fmt"
type TrieNode struct {
children [26]*TrieNode
isEnd bool
}
func insert(root *TrieNode, word string) {
curr := root
for _, ch := range word {
index := ch - 'a'
if curr.children[index] == nil {
curr.children[index] = &TrieNode{}
}
curr = curr.children[index]
}
curr.isEnd = true
}
// DFS to collect all words in the Trie
func collectWords(node *TrieNode, prefix string) {
if node.isEnd {
fmt.Println(prefix) // found a complete word
}
for i := 0; i < 26; i++ {
if node.children[i] != nil {
nextChar := string(rune('a' + i))
collectWords(node.children[i], prefix+nextChar)
}
}
}
func listAllWords(root *TrieNode) {
collectWords(root, "")
}
func main() {
root := &TrieNode{}
insert(root, "cat")
insert(root, "car")
insert(root, "care")
insert(root, "dog")
insert(root, "do")
fmt.Println("All words in the Trie:")
listAllWords(root)
}
运行该程序将输出:
All words in the Trie:
car
care
cat
do
dog
完整实现
以下是将上述所有部分组合在一起的完整 Trie 程序。操作包括:插入单词、搜索单词、前缀搜索、列出所有单词、删除单词。
C++ 完整实现
#include <iostream>
#include <string>
using namespace std;
struct TrieNode {
TrieNode* children[26];
bool isEndOfWord;
TrieNode() {
for (int i = 0; i < 26; i++) children[i] = nullptr;
isEndOfWord = false;
}
};
class Trie {
private:
TrieNode* root;
void collectWords(TrieNode* node, string prefix) {
if (node->isEndOfWord)
cout << " " << prefix << endl;
for (int i = 0; i < 26; i++) {
if (node->children[i] != nullptr)
collectWords(node->children[i], prefix + char('a' + i));
}
}
TrieNode* deleteHelper(TrieNode* node, const string& word, int depth) {
if (node == nullptr) return nullptr;
if (depth == (int)word.size()) {
if (node->isEndOfWord)
node->isEndOfWord = false;
if (isEmpty(node)) {
delete node;
return nullptr;
}
return node;
}
int index = word[depth] - 'a';
node->children[index] = deleteHelper(node->children[index], word, depth + 1);
if (isEmpty(node) && !node->isEndOfWord) {
delete node;
return nullptr;
}
return node;
}
bool isEmpty(TrieNode* node) {
for (int i = 0; i < 26; i++)
if (node->children[i] != nullptr) return false;
return true;
}
public:
Trie() : root(new TrieNode()) {}
void insert(const string& word) {
TrieNode* curr = root;
for (char ch : word) {
int index = ch - 'a';
if (curr->children[index] == nullptr)
curr->children[index] = new TrieNode();
curr = curr->children[index];
}
curr->isEndOfWord = true;
}
bool search(const string& word) {
TrieNode* curr = root;
for (char ch : word) {
int index = ch - 'a';
if (curr->children[index] == nullptr) return false;
curr = curr->children[index];
}
return curr->isEndOfWord;
}
bool startsWith(const string& prefix) {
TrieNode* curr = root;
for (char ch : prefix) {
int index = ch - 'a';
if (curr->children[index] == nullptr) return false;
curr = curr->children[index];
}
return true;
}
void remove(const string& word) {
deleteHelper(root, word, 0);
}
void listAll() {
collectWords(root, "");
}
};
int main() {
Trie trie;
// insert words
trie.insert("cat");
trie.insert("car");
trie.insert("care");
trie.insert("dog");
trie.insert("do");
cout << "=== All words ===" << endl;
trie.listAll();
// search
cout << "\n=== Search ===" << endl;
cout << "Search 'cat': " << (trie.search("cat") ? "Found" : "Not found") << endl;
cout << "Search 'ca': " << (trie.search("ca") ? "Found" : "Not found") << endl;
cout << "Search 'cow': " << (trie.search("cow") ? "Found" : "Not found") << endl;
// prefix search
cout << "\n=== Prefix Search ===" << endl;
cout << "StartsWith 'ca': " << (trie.startsWith("ca") ? "Yes" : "No") << endl;
cout << "StartsWith 'do': " << (trie.startsWith("do") ? "Yes" : "No") << endl;
cout << "StartsWith 'ba': " << (trie.startsWith("ba") ? "Yes" : "No") << endl;
// delete
cout << "\n=== Delete 'car' ===" << endl;
trie.remove("car");
cout << "Search 'car': " << (trie.search("car") ? "Found" : "Not found") << endl;
cout << "Search 'care': " << (trie.search("care") ? "Found" : "Not found") << endl;
cout << "\n=== All words after deletion ===" << endl;
trie.listAll();
return 0;
}
运行该程序将输出:
=== All words ===
car
care
cat
do
dog
=== Search ===
Search 'cat': Found
Search 'ca': Not found
Search 'cow': Not found
=== Prefix Search ===
StartsWith 'ca': Yes
StartsWith 'do': Yes
StartsWith 'ba': No
=== Delete 'car' ===
Search 'car': Not found
Search 'care': Found
=== All words after deletion ===
care
cat
do
dog
C 完整实现
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef struct TrieNode {
struct TrieNode* children[26];
bool isEndOfWord;
} TrieNode;
typedef struct {
TrieNode* root;
} Trie;
TrieNode* createNode() {
TrieNode* node = (TrieNode*)malloc(sizeof(TrieNode));
for (int i = 0; i < 26; i++) node->children[i] = NULL;
node->isEndOfWord = false;
return node;
}
void trieInit(Trie* trie) {
trie->root = createNode();
}
void trieInsert(Trie* trie, const char* word) {
TrieNode* curr = trie->root;
for (int i = 0; word[i] != '\0'; i++) {
int index = word[i] - 'a';
if (curr->children[index] == NULL)
curr->children[index] = createNode();
curr = curr->children[index];
}
curr->isEndOfWord = true;
}
bool trieSearch(Trie* trie, const char* word) {
TrieNode* curr = trie->root;
for (int i = 0; word[i] != '\0'; i++) {
int index = word[i] - 'a';
if (curr->children[index] == NULL) return false;
curr = curr->children[index];
}
return curr->isEndOfWord;
}
bool trieStartsWith(Trie* trie, const char* prefix) {
TrieNode* curr = trie->root;
for (int i = 0; prefix[i] != '\0'; i++) {
int index = prefix[i] - 'a';
if (curr->children[index] == NULL) return false;
curr = curr->children[index];
}
return true;
}
bool isEmpty(TrieNode* node) {
for (int i = 0; i < 26; i++)
if (node->children[i] != NULL) return false;
return true;
}
TrieNode* deleteHelper(TrieNode* node, const char* word, int depth) {
if (node == NULL) return NULL;
if (depth == (int)strlen(word)) {
if (node->isEndOfWord)
node->isEndOfWord = false;
if (isEmpty(node)) {
free(node);
return NULL;
}
return node;
}
int index = word[depth] - 'a';
node->children[index] = deleteHelper(node->children[index], word, depth + 1);
if (isEmpty(node) && !node->isEndOfWord) {
free(node);
return NULL;
}
return node;
}
void trieDelete(Trie* trie, const char* word) {
trie->root = deleteHelper(trie->root, word, 0);
}
void collectWords(TrieNode* node, char* buffer, int depth) {
if (node->isEndOfWord) {
buffer[depth] = '\0';
printf(" %s\n", buffer);
}
for (int i = 0; i < 26; i++) {
if (node->children[i] != NULL) {
buffer[depth] = 'a' + i;
collectWords(node->children[i], buffer, depth + 1);
}
}
}
void trieListAll(Trie* trie) {
char buffer[256];
collectWords(trie->root, buffer, 0);
}
int main() {
Trie trie;
trieInit(&trie);
trieInsert(&trie, "cat");
trieInsert(&trie, "car");
trieInsert(&trie, "care");
trieInsert(&trie, "dog");
trieInsert(&trie, "do");
printf("=== All words ===\n");
trieListAll(&trie);
printf("\n=== Search ===\n");
printf("Search 'cat': %s\n", trieSearch(&trie, "cat") ? "Found" : "Not found");
printf("Search 'ca': %s\n", trieSearch(&trie, "ca") ? "Found" : "Not found");
printf("Search 'cow': %s\n", trieSearch(&trie, "cow") ? "Found" : "Not found");
printf("\n=== Prefix Search ===\n");
printf("StartsWith 'ca': %s\n", trieStartsWith(&trie, "ca") ? "Yes" : "No");
printf("StartsWith 'do': %s\n", trieStartsWith(&trie, "do") ? "Yes" : "No");
printf("StartsWith 'ba': %s\n", trieStartsWith(&trie, "ba") ? "Yes" : "No");
printf("\n=== Delete 'car' ===\n");
trieDelete(&trie, "car");
printf("Search 'car': %s\n", trieSearch(&trie, "car") ? "Found" : "Not found");
printf("Search 'care': %s\n", trieSearch(&trie, "care") ? "Found" : "Not found");
printf("\n=== All words after deletion ===\n");
trieListAll(&trie);
return 0;
}
运行该程序将输出:
=== All words ===
car
care
cat
do
dog
=== Search ===
Search 'cat': Found
Search 'ca': Not found
Search 'cow': Not found
=== Prefix Search ===
StartsWith 'ca': Yes
StartsWith 'do': Yes
StartsWith 'ba': No
=== Delete 'car' ===
Search 'car': Not found
Search 'care': Found
=== All words after deletion ===
care
cat
do
dog
Python 完整实现
class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word):
curr = self.root
for ch in word:
if ch not in curr.children:
curr.children[ch] = TrieNode()
curr = curr.children[ch]
curr.is_end_of_word = True
def search(self, word):
curr = self.root
for ch in word:
if ch not in curr.children:
return False
curr = curr.children[ch]
return curr.is_end_of_word
def starts_with(self, prefix):
curr = self.root
for ch in prefix:
if ch not in curr.children:
return False
curr = curr.children[ch]
return True
def _delete_helper(self, node, word, depth):
if node is None:
return None
if depth == len(word):
if node.is_end_of_word:
node.is_end_of_word = False
if not node.children:
return None
return node
ch = word[depth]
if ch in node.children:
node.children[ch] = self._delete_helper(
node.children[ch], word, depth + 1)
if node.children[ch] is None:
del node.children[ch]
if not node.children and not node.is_end_of_word:
return None
return node
def delete(self, word):
self._delete_helper(self.root, word, 0)
def _collect_words(self, node, prefix, result):
if node.is_end_of_word:
result.append(prefix)
for ch in sorted(node.children.keys()):
self._collect_words(node.children[ch], prefix + ch, result)
def list_all(self):
result = []
self._collect_words(self.root, "", result)
return result
if __name__ == '__main__':
trie = Trie()
trie.insert("cat")
trie.insert("car")
trie.insert("care")
trie.insert("dog")
trie.insert("do")
print("=== All words ===")
for word in trie.list_all():
print(f" {word}")
print("\n=== Search ===")
print(f"Search 'cat': {'Found' if trie.search('cat') else 'Not found'}")
print(f"Search 'ca': {'Found' if trie.search('ca') else 'Not found'}")
print(f"Search 'cow': {'Found' if trie.search('cow') else 'Not found'}")
print("\n=== Prefix Search ===")
print(f"StartsWith 'ca': {'Yes' if trie.starts_with('ca') else 'No'}")
print(f"StartsWith 'do': {'Yes' if trie.starts_with('do') else 'No'}")
print(f"StartsWith 'ba': {'Yes' if trie.starts_with('ba') else 'No'}")
print("\n=== Delete 'car' ===")
trie.delete("car")
print(f"Search 'car': {'Found' if trie.search('car') else 'Not found'}")
print(f"Search 'care': {'Found' if trie.search('care') else 'Not found'}")
print("\n=== All words after deletion ===")
for word in trie.list_all():
print(f" {word}")
运行该程序将输出:
=== All words ===
car
care
cat
do
dog
=== Search ===
Search 'cat': Found
Search 'ca': Not found
Search 'cow': Not found
=== Prefix Search ===
StartsWith 'ca': Yes
StartsWith 'do': Yes
StartsWith 'ba': No
=== Delete 'car' ===
Search 'car': Not found
Search 'care': Found
=== All words after deletion ===
care
cat
do
dog
三个语言版本的输出完全一致。删除 "car" 后,"care" 依然保留,说明共享前缀的节点被正确保护;"cat", "do", "dog" 不受影响。
Go 完整实现
package main
import "fmt"
type TrieNode struct {
children [26]*TrieNode
isEnd bool
}
type Trie struct {
root *TrieNode
}
func NewTrie() *Trie {
return &Trie{root: &TrieNode{}}
}
func (t *Trie) Insert(word string) {
curr := t.root
for _, ch := range word {
index := ch - 'a'
if curr.children[index] == nil {
curr.children[index] = &TrieNode{}
}
curr = curr.children[index]
}
curr.isEnd = true
}
func (t *Trie) Search(word string) bool {
curr := t.root
for _, ch := range word {
index := ch - 'a'
if curr.children[index] == nil {
return false
}
curr = curr.children[index]
}
return curr.isEnd
}
func (t *Trie) StartsWith(prefix string) bool {
curr := t.root
for _, ch := range prefix {
index := ch - 'a'
if curr.children[index] == nil {
return false
}
curr = curr.children[index]
}
return true
}
func (t *Trie) Remove(word string) {
t.deleteHelper(t.root, word, 0)
}
func (t *Trie) deleteHelper(node *TrieNode, word string, depth int) *TrieNode {
if node == nil {
return nil
}
if depth == len(word) {
if node.isEnd {
node.isEnd = false
}
if isEmpty(node) {
return nil
}
return node
}
index := word[depth] - 'a'
node.children[index] = t.deleteHelper(node.children[index], word, depth+1)
if isEmpty(node) && !node.isEnd {
return nil
}
return node
}
func (t *Trie) ListAll() {
t.collectWords(t.root, "")
}
func (t *Trie) collectWords(node *TrieNode, prefix string) {
if node.isEnd {
fmt.Printf(" %s\n", prefix)
}
for i := 0; i < 26; i++ {
if node.children[i] != nil {
nextChar := string(rune('a' + i))
t.collectWords(node.children[i], prefix+nextChar)
}
}
}
func isEmpty(node *TrieNode) bool {
for i := 0; i < 26; i++ {
if node.children[i] != nil {
return false
}
}
return true
}
func foundStr(found bool) string {
if found {
return "Found"
}
return "Not found"
}
func yesNo(val bool) string {
if val {
return "Yes"
}
return "No"
}
func main() {
trie := NewTrie()
// insert words
trie.Insert("cat")
trie.Insert("car")
trie.Insert("care")
trie.Insert("dog")
trie.Insert("do")
fmt.Println("=== All words ===")
trie.ListAll()
// search
fmt.Println("\n=== Search ===")
fmt.Printf("Search 'cat': %s\n", foundStr(trie.Search("cat")))
fmt.Printf("Search 'ca': %s\n", foundStr(trie.Search("ca")))
fmt.Printf("Search 'cow': %s\n", foundStr(trie.Search("cow")))
// prefix search
fmt.Println("\n=== Prefix Search ===")
fmt.Printf("StartsWith 'ca': %s\n", yesNo(trie.StartsWith("ca")))
fmt.Printf("StartsWith 'do': %s\n", yesNo(trie.StartsWith("do")))
fmt.Printf("StartsWith 'ba': %s\n", yesNo(trie.StartsWith("ba")))
// delete
fmt.Println("\n=== Delete 'car' ===")
trie.Remove("car")
fmt.Printf("Search 'car': %s\n", foundStr(trie.Search("car")))
fmt.Printf("Search 'care': %s\n", foundStr(trie.Search("care")))
fmt.Println("\n=== All words after deletion ===")
trie.ListAll()
}
运行该程序将输出:
=== All words ===
car
care
cat
do
dog
=== Search ===
Search 'cat': Found
Search 'ca': Not found
Search 'cow': Not found
=== Prefix Search ===
StartsWith 'ca': Yes
StartsWith 'do': Yes
StartsWith 'ba': No
=== Delete 'car' ===
Search 'car': Not found
Search 'care': Found
=== All words after deletion ===
care
cat
do
dog
Go 版本使用 Trie 结构体封装所有操作,通过 NewTrie() 构造函数初始化。方法接收者使用指针类型 *Trie,确保对内部状态的修改生效。输出与其他语言版本完全一致。
Trie 的性质
时间复杂度
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 插入(Insert) | O(m) | m 为待插入字符串的长度 |
| 搜索(Search) | O(m) | m 为待搜索字符串的长度 |
| 前缀搜索(StartsWith) | O(m) | m 为前缀长度 |
| 删除(Delete) | O(m) | m 为待删除字符串的长度 |
与哈希表(Hash Table)相比,Trie 的时间复杂度不依赖哈希函数,且不存在哈希冲突(Hash Collision)。与二叉搜索树(BST)相比,Trie 的查找不依赖字符串的全序比较,而是逐字符精确匹配。
空间复杂度
| 方面 | 复杂度 | 说明 |
|---|---|---|
| 最坏情况 | O(N * m) | N 为单词数,m 为平均长度,所有单词无公共前缀 |
| 最佳情况 | O(m) | 所有单词共享前缀,N 个单词仅需一条链 |
对于固定数组实现(如 children[26]),每个节点占用恒定空间。如果字符集更大(如 Unicode),应使用字典(dict)或哈希表实现子节点映射,以避免浪费内存。
实际应用
| 应用 | 说明 |
|---|---|
| 自动补全(Autocomplete) | 搜索引擎输入框的联想词功能。用户输入前缀后,Trie 可以快速定位到所有以该前缀开头的单词 |
| 拼写检查(Spell Checker) | 将字典中的所有单词存入 Trie,检查输入的单词是否存在即可判断拼写是否正确 |
| IP 路由(IP Routing) | 路由器使用 Trie 的变体(前缀树)进行最长前缀匹配,确定数据包的转发路径 |
| T9 文字输入(T9 Predictive Text) | 手机九宫格键盘的文字预测功能,基于 Trie 查找按键序列对应的所有可能单词 |
| 字符串排序(String Sorting) | 将所有字符串插入 Trie 后按字典序遍历,即可完成排序,时间复杂度为 O(N * m) |
| 基因序列分析(DNA Sequence Analysis) | 在生物信息学中,Trie 可用于存储和检索 DNA 序列(A, T, C, G)的公共前缀 |

浙公网安备 33010602011771号