Trie
Trie是指一个字符串集合对应的有根树,树的每条边对应一个字符,根节点表示空串,其他每个节点表示从根到这个节点的路径组成的字符串,在每个属于集合中的字符串的节点处打上标记
Trie是可以高效维护字符串集合,以空间换时间的数据结构,Trie中插入字符串和查询字符串的效率比较高,时间复杂度都是\(O(n)\),其中\(n\)为字符串的长度,但是建立Trie需要一定的空间,如果字符的种类为\(k\),则每个节点的出度都为\(k\)
Trie的结构
数组模拟Trie
const int maxn=500010;
int trie[maxn][30]; //节点i的第j个儿子的节点编号
bool terminal[maxn]; //以某个节点结尾是一个字符串
int tot; //总节点数
插入操作
对于一个待插入的字符串,从Trie的根开始,沿着单词的各个字母所对应的Trie中的节点分支向下走,直到单词遍历完,将最后的节点打上标记,表示已经将单词插入Trie
void insert(char* s){
int l=strlen(s);
int root=0;
for(int i=0;i<l;i++){
int id=s[i]-'a';
if(!trie[root][id]) trie[root][id]=++tot;
root=trie[root][id];
}
terminal[root]=true;
}
查询操作
对于一个待查询的字符串,从Trie的根开始按照字符串的字符顺序向下遍历Trie,如果一直可以遍历到字符串结束,并且字符串结尾的节点具有标记,说明查找成功,否则说明某个节点不存在或者字符串末尾节点没有标记,查找失败
bool find(char* s){
int l=strlen(s);
int root=0;
for(int i=0;i<l;i++){
int id=s[i]-'a';
if(!trie[root][id]) return false;
root=trie[root][id];
}
return true;
}
Trie结构体
struct Trie{
struct node{
int nxt[26];
int cnt;
int v;
void init(){
memset(nxt,0,sizeof(nxt));
v=0;
cnt=0;
}
}t[maxm];
int root,tot;
int newnode(){
++tot;
t[tot].init();
return tot;
}
void init(){
tot=0;
root=newnode();
}
void insert(char *s,LL v) {
int len=strlen(s);
int now=root;
for(int i=0;i<len;i++){
int id=s[i]-'a';
if(!t[now].nxt[id]) {
t[now].nxt[id]=newnode();
}
now=t[now].nxt[id];
}
t[now].v+=v;
t[now].cnt++;
}
int query(char *s){
int len=strlen(s);
int now=root;
for (int i=0;i<len;i++){
int id=s[i]-'a';
now=t[now].nxt[id];
}
return t[now].v;
}
}trie;
模板题
hdu1251 统计难题
统计以某个字符串为前缀的字符串个数
hdu2072 单词数
统计一些字符串中不同字符串的种类

浙公网安备 33010602011771号