字典树
Posted zllwxm123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字典树相关的知识,希望对你有一定的参考价值。
字典是干啥的?查找字的。
字典树自然也是起查找作用的。查找的是啥?单词。
看以下几个题:
1、给出n个单词和m个询问,每次询问一个单词,回答这个单词是否在单词表中出现过。
答:简单!map,短小精悍。
好。下一个
2、给出n个单词和m个询问,每次询问一个前缀,回答询问是多少个单词的前缀。
答:map,把每个单词拆开。
judge:n<=200000,TLE!
这就需要一种高级数据结构——Trie树(字典树)
假设所有单词都只由小写字母构成
对cat,cash,app,apple,aply,ok 建一颗字典树,建成之后如下图所示
由此可以看出:
1、字典树用边表示字母
2、有相同前缀的单词公用前缀节点,那我们可以的得出每个节点最多有26个子节点(在单词只包含小写字母的情况下)
3、整棵树的根节点是空的。为什么呢?便于插入和查找,这将会在后面解释。
4、每个单词结束的时候用一个特殊字符表示,图中用的‘′,那么从根节点到任意一个‘′,那么从根节点到任意一个‘’所经过的边的所有字母表示一个单词。
A、insert,插入一个单词
1.思路
从图中可以直观看出,从左到右扫这个单词,如果字母在相应根节点下没有出现过,就插入这个字母;否则沿着字典树往下走,看单词的下一个字母。
这就产生一个问题:往哪儿插?计算机不会自己选择位置插,我们需要给它指定一个位置,那就需要给每个字母编号。
我们设数组trie[i][j]=k,表示编号为i的节点的第j个孩子是编号为k的节点。
什么意思呢?
这里有2种编号,一种是i,k表示节点的位置编号,这是相对整棵树而言的;另一种是j,表示节点i的第j的孩子,这是相对节点i而言的。
不理解?看图
还是单词cat,cash,app,apple,aply,ok
我们就按输入顺序对其编第一种号,红色表示编号结果。因为先输入的cat,所以c,a,t分别是1,2,3,然后输入的是cash,因为c,a是公共前缀,所以从s开始编,s是4,以此类推。
注意这里相同字母的编号可能不同
第二种编号,相对节点的编号,紫色表示编号结果。
因为每个节点最多有26个子节点,我们可以按他们的字典序从0——25编号,也就是他们的ASCLL码-a的ASCLL码。
注意这里相同字母的编号相同
实际上每个节点的子节点都应该从0编到——25,但这样会发现许多事根本用不到的。比如上图的根节点应该分出26个叉。节约空间,用到哪个分哪个。
这样编号有什么用呢?
回到数组trie[i][j]=k。 数组trie[i][j]=k,表示编号为i的节点的第j个孩子是编号为k的节点。
那么第二种编号即为j,第一种编号即为i,k
建树;
结构体方法:建树加插入
struct node{ bool flag; struct *next[26]; }*next; void insert(char *s){ node *p = root; for(int i=0;s[i];i++){ int x = s[i]-‘a‘; if(p->next[x]==NULL){ p->next[x] = new node; } p = p->next[x]; } p->flag = true; }
查找find:
bool find(char *s){ node *p = root; for(int i=0;s[i];i++){ int x = s[i]-‘a‘; if(p->next[x]==NULL){ return false; } p = p->next[x]; } return true; }
用指针大多数要释放内存:
void delete(node *p){ if(p!=NULL){ for(int i=0;i<26;i++){ if(p->next[i]!=NULL){ delete(p->next[i]); } } }else return ; free(p); return ; }
用数组表示:
建树+插入
int tree[100000*26][26]; int val[100000*26]; int pos = 1; void insert(char *s){ int root = 0; for(int i=0;s[i];i++){ int x = s[i]-‘a‘; if(!tree[root][x]){ tree[root][x] = pos++; } root = tree[root][x]; } val[root] = 1; }
查找:
bool find(char *s){ int root = 0; for(int i=0;s[i];i++){ int x = s[i]-‘a‘; if(!tree[root][x]){ return 0; } root = tree[root][x]; } return val[root]; }
以上是关于字典树的主要内容,如果未能解决你的问题,请参考以下文章