Trie树(字典树)整理

字典树 (Trie)

用于存储字符串。树的每条边恰好表示一个字符,每个节点代表从根到该节点的路径所对应的字符串。

简介与操作实现可见蓝书P82~83。

  Trie字典树很好地利用了前缀,节省了很多空间。

 1 //先说明一下:本代码段的字符串d的下标都是从1开始
 2 inline void insert(char *d)//向Trie树插入字符串d 
 3 {
 4     int l=strlen(d+1),now=0,num;
 5     for(int i=1;i<=l;++i)
 6     {
 7         num=d[i]-'a';//字符化为数字下标 
 8         if(!tree[now][num])//当前节点不存在该字母的边,即该字母还未在当前节点插入过 
 9             tree[now][num]=++cnt;
10         now=tree[now][num];
11     }
12     ed[now]=1;//最后标明一下字符串结尾节点,说明该节点代表了一个已插入过的字符串 
13 }
14 
15 inline int fin(char *d)从Trie树查询字符串d 
16 {
17     int  l=strlen(d+1),now=0,num;
18     for(int i=1;i<=l;++i)
19     {
20         num=d[i];
21         if(!tree[now][num])//不存在对应节点了,说明Trie中没有这个串
22             return 0;
23         now=tree[now][num];
24     }
25     return ed[now];//查询到最后还要看当前节点是否代表一个插入过Tire树的字符串
26 }
操作实现的核心代码

应用:

1、前缀查找。

  在Trie树中查找一个字符串的前缀。不管Trie树中插入了多少个字符串,查找的复杂度都是优秀的O(n)(n为当前字符串的长度)。

  还有一种边插边找前缀的方法。如果当前串插入Trie树时没有新建任何节点,那它就是它的末尾节点的子树中所有串的前缀;如果当前串插入Trie树时经过了某个串x的末尾节点,那么x就是当前串的一个前缀。

2、异或相关。

  将每个数看做二进制的01串。从Trie树中找当前数字异或值最大的数,只要尽可能向与当前边反方向的边走就好。

 1 inline int fin(int a)//从Trie树中找与a异或的结果最大的数,并返回这个结果
 2                      //a为int范围的一个正整数 
 3 {
 4     int ret=0,c,now=1;//这里的Trie数根节点的编号为1 
 5     for(int k=30;k>=0;--k)
 6     {
 7         if((a&(1<<k))^(1<<k))//看下a当前位取反的结果 
 8             c=1;
 9         else
10             c=0;
11         if(tree[now][c])//当前点能有a当前位代表边的另一侧方向的边的话,就走那条边 
12         {
13             now=tree[now][c];
14             ret|=1<<k;//维护答案(当前走的与a的当前位不一样的话,答案的当前位就是1,因为是异或) 
15         }
16         else//没有的话,有哪条边,就走那条边喽。
17             //Trie树中至少有一个数的话,一定能一直走下去 
18             now=tree[now][c^1];
19     }
20     return ret;
21 }
相关代码

 

posted @ 2019-11-06 21:47  千叶繁华  阅读(137)  评论(0编辑  收藏  举报