插入:得到待插入字符串的长度,每次从上到下生成节点插入进去(就是相当于尾插法生成链表),但如果我们要生成的节点本来就已经有了,那么我们就直接到下面的节点里去。 在这个步骤的循环中,每次都要把当前节点的pass+1,表示有一个串要经过该节点。 到了最终的尾节点,把end+1;
删除:正常是,每次对当前节点进行查询下一个节点的位置,把当前节点的pass-1,然后去到下一个节点,一直走到子串的最后一个元素,把该元素的end-1,表示:一个子串被删除了。
优化:每次我们都判断当前节点pass是不是只剩1了,若只剩1,那么扣除我当前走的子串,这里的pass就变成0了,意思是这个节点后面没人走了,我们就可以在当前节点里把 当前字符所对应的节点删去,然后结束。
查询: 每次对当前节点查询其下一个节点,若下一个节点不在,则返回0,若在,则一路往下走,知道到达子串的最后一个节点,返回该节点的end,表示有几个串以当前节点结尾。
前缀查询:每次对当前节点查询其下一个节点,若下一个节点不在,则返回0,若在,则去到下一个节点。 直到我们到达串中的最后一个节点,此时返回该节点的pass,表示后面还有几个串经过该节点。
#include<iostream>
#include<unordered_map>
#include<string>
using namespace std;
struct Node{
char c;
int pass;
int end;
unordered_map<char,Node*> map;
Node(){
pass = 0;
end = 0;
}
Node(char c){
this->c = c;
pass = 0;
end = 0;
}
unordered_map<char,Node*> getMap(){
return map;
}
};
class PrefixTree{
private:
Node* head;
public:
PrefixTree(){
head = new Node();
}
void insert(string str){
char* p = (char*)str.data();
int length = str.size();
char c;
Node* help = head;
for(int i=0;i<length;i++){
c = *(p+i);
//该节点下面多了一个相连,则pass++
help->pass++;
//head中没有指向c这个字符的指向,那么就生成一个加入到该节点的map里
if(help->map.find(c) == help->map.end() ){
Node* node = new Node(c);
help->map[*(p+i)] = node;
}
//map里有下位节点后,走向该节点
help = help->map.find(c)->second;
}
//最终 end+1
help->end++;
}
int search(string str){
char* p = (char*)str.data();
int length = str.size();
char c;
Node* help = head;
if(str.size() == 0)
return 0;
for(int i=0; i<length;i++){
c = *(p+i);
// 如果没有对应的下层节点,则直接返回0
if(help->map.find(c) == help->map.end())
return 0;
help = help->map.find(c)->second;
}
return help->end;
}
void delete_(string str){
if(search(str) > 0){
char* p = (char*)str.data();
int length = str.size();
char c;
Node* help = head;
for(int i=0;i<length;i++){
c = *(p+i);
if(--(help->pass) == 0){
//说明扣除掉这个字符串后,该节点之后的元素也没用了,所以整串都去掉
help->map.erase(c);
return ;
}
//去下一个节点
help = help->map.find(c)->second;
}
help->end--;
}
}
int prefixNumber(string str){
if(str.size() == 0)
return 0;
char* p = (char*)str.data();
int length = str.size();
Node* help = head;
char c;
for(int i=0;i<length;i++){
c = *(p+i);
if(help->map.find(c) == help->map.end())
return 0;
help = help->map.find(c)->second;
}
return help->pass;
}
int getHeadpass(){
return head->pass;
}
};
int main(){
PrefixTree pft;
// cout << "插入 abc "<<endl;
// pft.insert("abc");
// cout <<"插入后,能找到 abc:" <<pft.search("abc")<<endl;
// pft.delete_("abc");
// cout <<"删除abc后,找abc: "<< pft.search("abc")<<endl;
cout << "插入 abc "<<endl;
pft.insert("abc");
cout << "插入 abd "<<endl;
pft.insert("abd");
cout <<"以ab为前缀的 子串有 " <<pft.prefixNumber("ab") << " 个"<<endl;
pft.delete_("abc");
cout <<"以ab为前缀的 子串有 " <<pft.prefixNumber("ab") << " 个"<<endl;
return 0;
}