【Trie(字典树)--模板】学习

来源:互联网 发布:淘宝答题秒杀辅助工具 编辑:程序博客网 时间:2024/05/21 09:05

今天早上学习字典树,学了一上午懂了思想。


一、儿子节点表示法

代码是学习大佬的,数组实现字典树;

next [ NODE ] [ 26 ] : 

NODE是节点编号 ,后面26指的是每个节点都有26个分叉,if next[ i ] [ j ]==1 ,意思是说到    编号i的字母   到达   j 对应的字母 是 ok 的;

如果加上了算法头文件,则数组名为 next 会CE!

v [ NODE ] :

v  数组用来保存各节点的信息;

#define NODE 1000005int next[NODE][26];int v[NODE];int node;void init()  //初始化;{    node=1;  //节点个数;    memset(next[0],0,sizeof(next[0]));}void add(char *str)  //加入{    int cur=0,k;    int len=strlen(str);    for(int i=0;i<len;i++)    {        k=str[i]-'a';        if(next[cur][k]==0)        {            memset(next[node],0,sizeof(node));            v[node]=0;  //清空操作;            next[cur][k]=node++;        }        cur=next[cur][k];        v[cur]++;    }}int cal(char *str)  //查询{    int cur=0,k;    int len=strlen(str);    for(int i=0;i<len;i++)    {        k=str[i]-'a';        if(next[cur][k])            cur=next[cur][k];        else            return 0;    }    return v[cur];}
// 注意在这里v[ i ] 存的是到达 编号为 i 的这个节点次数;

可以对着下图模拟一波代码:

两个字符串nyoj 、nyist  ,


二、左儿子右兄弟表示法

由于儿子节点表示法会将很多的节点白白浪费,耗用了大量的空间。左儿子右兄弟表示法以时间换空间节省内存,利用该表示法建成的是一棵二叉树,每个节点的左儿子节点代表儿子,右儿子节点表示兄弟;

代码:

#include<bits/stdc++.h>#define N 1010struct node{    char c;    int l,r;    int val,cut;}trie[N+10];int node;void init(){    node=1;    memset(trie,0,sizeof(trie));}void add(char *s){    int rt,i;    for(rt=0;*s;s++,rt=i)    {        for(i=trie[rt].l;i;i=trie[i].r)        {            if(trie[i].c==*s)                break;        }                if(i==0)        {            trie[node].r=trie[rt].l;            trie[node].l=0;            trie[node].c=*s;            trie[node].val++;            trie[rt].l=node;            i=node++;        }    }    trie[rt].cut++;        return 0;}int cal(char *s){    int rt;    for(rt=0;*s;s++)    {        for(rt=trie[rt].l;rt;rt=trie[rt].r)        {            if(trie[rt].c==*s)                break;        }        if(rt==0)            return 0;    }    return ~;}

模拟这份代码的时候总搞不懂,比如nyoj,nyist构建二叉树的过程:


----------------------


o节点被挤到i的右兄弟上了,明白了这一点就模拟好代码了;


三、01二叉树模板

题目类型 基本与异或相关,比如求序列两两亦或最大值、序列连续异或最大值等;

异或规则 是:相同为0,不同为1;

给定一个数x,为了得到异或后的最大值尽量寻找与 x 同位相异的数字,把数字转化为二进制串即01串,把这个串插入字典树中,要从高位开始插入,贪心思想!

代码:

int nex[N][2];int val[N],num[N];int node;void init(){    node=1;    memset(nex[0],0,sizeof(nex[0]));}void add(int c){    int cur=0,k;    for(int i=31;i<=0;i--)    {        k=(c>>i)&1;        if(!nex[cur][k])        {            memset(nex[node],0,sizeof(nex[node]));            val[node]=cut[node]=0;                        nex[cur][k]=node++;        }        cur=nex[cur][k];        num[cur]++;    }    val[cur]=c;}int cal(int c){    int cur=0,k;    for(int i=31;i<=0;i--)    {        k=(c>>i)&1;        if(nex[cur][1-k])     //同位相异,1-0=1,1-1=0;            cur=nex[cur][1-k];        else            cur=nex[cur][k];    }    return c^val[cur];}


小结:

经常保存的信息为:①某个节点用的次数 ②某个节点作为串的尾节点次数

原创粉丝点击