字典树 (Trie)ide
用于存储字符串。树的每条边刚好表示一个字符,每一个节点表明从根到该节点的路径所对应的字符串。spa
简介与操做实现可见蓝书P82~83。3d
Trie字典树很好地利用了前缀,节省了不少空间。code
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 }
应用:blog
一、前缀查找。字符串
在Trie树中查找一个字符串的前缀。无论Trie树中插入了多少个字符串,查找的复杂度都是优秀的O(n)(n为当前字符串的长度)。event
还有一种边插边找前缀的方法。若是当前串插入Trie树时没有新建任何节点,那它就是它的末尾节点的子树中全部串的前缀;若是当前串插入Trie树时通过了某个串x的末尾节点,那么x就是当前串的一个前缀。class
二、异或相关。cli
将每一个数看作二进制的01串。从Trie树中找当前数字异或值最大的数,只要尽量向与当前边反方向的边走就好。bfc
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 }