字典树又称为前缀树,是一种用来统计字符串前缀数目的数据结构,字典树的实现相对于线段树等数据结构还是比较简单。
字典树的有3个核心函数,insert , search ,delete。
实现字典树常用的方式有俩种,一个是结构体+指针,还用一种是二维数组模拟,思想都是一样的。
1、首先定义字典树的节点:
class node{ public: int path; int end; node *mp[26]; node (){ path=end=0; for (int i=0;i<26;i++) mp[i]=NULL; } };
节点中的path用来记录该节点被几个字符串用过。end用来记录以该节点结尾的字符串的个数。node *mp[26]是一个指针数组,我们可以用该数组记录该节点指向的下一个节点,数组大小为26指的是从a~z 26个英文字母,这个可以根据自己的寻求更改。比如说 x->mp[i]指的是节点x指向下一个值为i的节点。
2、节点的插入。
node *root = new node(); void insert(string s){ node *now=root; int n=s.size(); for(int i=0;i<n;i++){ int id=s[i]-'a'; if(root->mp[id]==NULL){ root->mp[id]=new node(); } root=root->mp[id]; root->path++; } root->end++; root=now; }
首先定义一个根节点指针。然后遍历字符串S的每一个字符,root->mp[id]!=NULL,说明遍历到目前为止,前缀字符串曾经出现过,即我们之前保存过的字符串和该字符串有共同的前缀。 如果root->mp[id]==NULL,说明该前缀第一次出现,要新申请一个节点用来保存当前字符,并作为上一个节点的儿子节点。root->path++; path记录的是该节点被几个字符串用过。没用一次+1就可以了。插入完之后 root->end++; 说明该节点为当前字符串的终止节点。
3、字符串的查找
int search(string s){ node *now=root; int n=s.size(); for(int i=0;i<n;i++){ int id=s[i]-'a'; if(now->mp[id]!=NULL){ now=now->mp[id]; } else return 0;//不存在. } return now->path; }
查找保存过的字符串无非就是根据字符串s,从root出发能不能找到一条路径。如果找着找着没路了,即S没有遍历完遇到了NULL,那就没找到喽,否则返回path,意思的有树中哟普几个以该字符串为前缀的字符串。
4、字符串的删除
void de(string s){ node *now=root; int n=s.size(); for(int i=0;i<n;i++){ int id=s[i]-'a'; root->mp[id]->path--; if(root->mp[id]->path==0){ root->mp[id]=NULL; return ; } root=root->mp[id]; } root->end--; root=now; }
如果我们想要删除之前保存过的字符串,只需要修改每个节点的path,如果说该节点的path为0了,直接将指针指为空即可并退出,如果没有遇到path=0的情况,在最后节点的end--,说明以该节点为结尾的字符串减一。
class node{ public: int path; int end; node *mp[26]; node (){ path=end=0; for (int i=0;i<26;i++) mp[i]=NULL; } }; node *root = new node(); void insert(string s){ node *now=root; if(root==NULL) return ; int n=s.size(); for(int i=0;i<n;i++){ int id=s[i]-'a'; if(root->mp[id]==NULL){ root->mp[id]=new node(); } root=root->mp[id]; root->path++; } root->end++; root=now; } int search(string s){ node *now=root; int n=s.size(); for(int i=0;i<n;i++){ int id=s[i]-'a'; if(now->mp[id]!=NULL){ now=now->mp[id]; } else return 0;//不存在. } return now->path; } void de(string s){ node *now=root; int n=s.size(); for(int i=0;i<n;i++){ int id=s[i]-'a'; root->mp[id]->path--; if(root->mp[id]->path==0){ root->mp[id]=NULL; return ; } root=root->mp[id]; } root->end--; root=now; }
root->path++;