LeetCode-208.实现Trie(前缀树)
初识前缀树,以前也想过编译器补全与拼写检查是如何实现,今天每日一题碰到了前缀树,终于初步了解机制了,所以分享下
前缀树是一颗多叉树,如果多个字符串有相同的前缀的话,就共用一条前缀,每个字符串也可以看做一条链表,所以前缀树可以看成多个链表共用前缀的多叉链表。
前缀树的数据结构:
struct Trie{
bool isEend;//字符串链表结束标志
//最主要的是理解下面的字母映射机制
struct Trie *next[26];//字母映射表,如果这个字母存在则有其对应的指针,负责为空
};
前缀树的插入、查找、检测前缀其实思路很简单,就是一趟遍历的事
插入:
//前缀树有个头结点
Trie *node = this;//this指针指向根节点,根节点为头结点,起辅助作用
for(char c:word){
//查看头结点下一个字符的指针,如果为空则说明不存在,创建这个指针
if(node->next[c - 'a'] == nullptr){
node->next[c - 'a'] = new Trie();
}
node = node->next[c - 'a'];
}
//最后一个字符设置结束标志
node->isEnd = true;
查找:
bool search(string word) {
Trie *node = this;
for(char c:word){
//这个字符的指针为空,则说明 没有这个字符,也就没有这个完整的字符串
if(node->next[c - 'a'] == nullptr){
return false;
}else{
node = node->next[c - 'a'];
}
}
return node->isEnd;
}
查看前缀:
和查找就只有最后一步不一样,这里只是找前缀
bool startsWith(string prefix) {
Trie *node = this;
for(char c:prefix){
if(node->next[c - 'a'] == nullptr){
return false;
}else{
node = node->next[c - 'a'];
}
}
return true;
}
具体实现:
class Trie {
private:
bool isEnd;
Trie *next[26];
public:
Trie() {
isEnd = false;
memset(next,0,sizeof(next));
}
void insert(string word) {
//刚开始设置一个头结点
Trie *node = this;
for(char c:word){
//查看头结点下一个字符的指针,如果为空则说明不存在,创建这个指针
if(node->next[c - 'a'] == nullptr){
node->next[c - 'a'] = new Trie();
}
node = node->next[c - 'a'];
}
//最后一个字符设置结束标志
node->isEnd = true;
}
bool search(string word) {
Trie *node = this;
for(char c:word){
if(node->next[c - 'a'] == nullptr){
return false;
}else{
node = node->next[c - 'a'];
}
}
return node->isEnd;
}
bool startsWith(string prefix) {
Trie *node = this;
for(char c:prefix){
if(node->next[c - 'a'] == nullptr){
return false;
}else{
node = node->next[c - 'a'];
}
}
return true;
}
};
前缀树只要理解了数据结构就很好理解