字典树(前缀树):
1. 定义前缀树结构:
struct Node{
char dir;
bool wordend; // 用于记录是否是一个单词的结尾
struct Node* child[26]; // 用于存储指向下一个字符的指针
};
主要包含三个部分,当前节点表示的字母,当前节点是否是单词结尾,以及指向子节点的指针,26个代表每个字母后面可以接任意字母
2. 字典树的插入操作(一开始就查看子节点,是因为根节点为空节点,不存储字母)
对插入单词进行遍历
(1)如果当前字母存在子节点中,那么进入子节点,继续遍历,进入子节点
(2)如果当前字母不再子节点中,那么新建子节点,并将该字母传入给子节点,并进入子节点
(3) 循环执行插入(1)(2)直到单词结尾处,将单词结尾处的子节点wordend标记为true,表示单词结尾
3. 字典树的查询操作
对查询单词循环遍历,挨个查询单词中的字母
(1)如果当前字母在子结点中,那么进入子节点,如果不在子结点中(子节点为NULL)那么没有该单词,返回false
(2)如果遍历到单词结尾的字母,存在于子结点中并且该子节点的wordend=true表名该单词在树中,返回true,其他情况皆为false
4. 字典树的前缀查询
与3相同,只不过不再需要判断是否是单词结尾,如果有则返回true
代码如下:
class Trie {
public:
struct Node{
char dir;
bool wordend; // 用于记录是否是一个单词的结尾
struct Node* child[26]; // 用于存储指向下一个字符的指针
};
struct Node* root;
Trie() {
root = new struct Node();
}
// 插入操作
void insert(string word) {
struct Node* curr = root;
for(int i=0;i<word.size();i++){
char c = word[i];
// 属于字符c的子节点为空,那么插入c
if(curr->child[c-'a']==NULL){
curr->child[c-'a'] = new struct Node();
}
// 进入下一个节点
curr = curr->child[c-'a'];
// 如果当前节点是字符串最后一个,那么将其标记为单词结尾
if(i==word.size()-1){
curr->wordend = true;
}
}
}
// 查找当前单词
bool search(string word) {
struct Node* curr = root;
for(int i=0;i<word.size();i++){
char c = word[i];
// 如果当前字符在字典中存在,那么进入下一个节点,如果不存在则返回false
if(curr->child[c-'a']!=NULL){
curr = curr->child[c-'a'];
// 查看当前字符是否是结尾字符
if(i==word.size()&&curr->wordend ==true){
return true;
}else if(i==word.size()-1&&curr->wordend!=true){
return false;
}
}else{
return false;
}
}
return true;
}
// 查询前缀的话,则只需要查看是否存在该前缀不需要判断是否是字符的结尾即可
bool startsWith(string prefix) {
struct Node* curr = root;
for(int i=0;i<prefix.size();i++){
char c = prefix[i];
if(curr->child[c-'a']!=NULL){
curr = curr->child[c-'a'];
if(i==prefix.size()-1){
return true;
}
}else{
return false;
}
}
return true;
}
};
/**
* Your Trie object will be instantiated and called as such:
* Trie* obj = new Trie();
* obj->insert(word);
* bool param_2 = obj->search(word);
* bool param_3 = obj->startsWith(prefix);
*/