Trie树简单讲解

字典树(Trie Tree)

trie树就是用来对于大量的文本统计,储存与查找的一种数据结构,下面简单介绍两种trie树的实现方式。


  • 多叉trie树

对于一个字符集大小为 S S 的文本,我们可以建立一棵S叉树,将文本统计。

具体实现如下:

首先我们对于一个节点,开一个大小为 S S 的数组,来表示它对于的子节点。比如对于小写字母的字符集,大小为26,我们就可以定义如下的节点:(我们将 a a ~z重新编号为 0 0 ~25)

struct node{
    int son[26];
    int flag;
};

其中 son[i] s o n [ i ] ,表示当前这个节点下一个字母编号为 i i 所对应的节点的编号,我们是将字母放在边上的。

所以对于一个字符串,我们可以用O(len)的时间插入到trie树中, len l e n 为字符串长度。

int tot;//表示节点个数
node trie[N];/trie树节点
int getid(char c){return c-'a';}
//获取字符编号
void insert(char *s,int len){
    int nowid=0;//当前的节点编号,这里我们把0号点当做根节点。
    for(int i=0,j;i<len;i++){
        j=getid(s[i]);//获取当前的字符编号
        if(!trie[nowid].son[j])
            trie[nowid].son[j]=++tot;//如果没有该结点,那么就将新建一个节点,节点个数增加。
        nowid=trie[nowid].son[j];
        //走到下一个节点。
    }
    trie[nowid].flag++;
    //将结束位置做上标记,表示有一个字符串在这里结束。
}

而我们发现,当字符集很大时,空间复杂度最坏是 len×S l e n × S 的,所以有没有更好的方法呢?下面就来介绍第二种。

  • 链表式trie树(时间换空间法)

我们可以像建图一样,将trie树建出,而没出现的节点就可以不用建,那么将大大节省空间复杂度,但是也有坏处就是我们不能 O(1) O ( 1 ) 的查找某一个节点对应的下一个某个字母的节点编号,而是需要去遍历所以的子节点,但是有时候时间换空间是明智的。

具体实现是类似的,但是在这里我们就不定义节点,可以定义一个边,如下:

struct side{
    int to,next;
    char c;//记录每条边对应的字符
};
int head[M],cnt;
//to表示下一个节点的编号和next表示链表的指针。
//head表示链表的表头,cnt记录边数

那么增加一条边就简单了:

side g[N];
void add(int a,int b,char c){
    g[++cnt]=(side){b,head[a],c};head[a]=cnt;
}

然后插入一个字符串的方式同第一种,只是细节变化了一点。

int flag[N];//记录节点标记
int tot;//表示节点个数
void insert(char *s,int len){
    int nowid=0,pos;//同样的0为根节点,pos记录下一个边的编号。
    for(int i=0;i<len;i++){
        for(pos=head[nowid];pos;pos=g[e].next){
            if(g[pos].c==s[i])break;
        }//去寻找下一个节点的编号
        if(!pos){
            add(nowid,++tot,s[i]);
            pos=cnt;
        }
        nowid=g[pos].to;
    }
    flag[nowid]++;
}

这就是两种trie树的方法啦!QAQ有错请指出


例题:


应用技巧:

其实trie树大多都是运用在AC自动机上面,然后夹杂一些其他的例如DP之类的。

trie树的特殊应用:可以来求异或最大值,方法就是将所有数字转换成二进制插入trie树,这时的trie树就变成了一个二叉树,然后异或最大就按照高位到低位贪心的在trie树上找一遍就好了。

下面附上一个AC自动机学习和trie树学习的神器

Go To Download密码xbj6

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VictoryCzt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值