trie字典树
trie树:高效存储,查找字符串集合

特点:通常只含小写字母或数字等,这个决定了一个节点可能延申出去的根最多是多少
0号点既是根节点,又是空节点
son[i][j]存储树中某个节点的子节点的id,i代表爸爸节点的id,j表示i节点下的第几个孩子。 比如我们输入一串只有小写英文字母的串,这意味一个节点下最多只可能有26个孩子(j的范围0-25)
所以,son[爸爸id][儿子在儿子们中的位置]=儿子id
cnt[]存储以每个节点结尾的单词数量。注意到某个单词末尾只能对应一个单词,所以用cnt储存单词出现次数是合理的
储存逻辑;son[p][u] 表示当前节点 p 的子节点 u(对应字母 a-z)。若子节点不存在(值为 0),则动态分配新节点(++idx)
举例,存入abc和abd,a-z分别代表j的0-25
从零节点开始son[0][0]代表a分支,最开始不存在,创建,并赋值为1(++idx),这时候i变为1,代表a的id,son[1][1]代表b,不存在,创建,赋值为2,c类似。这时第一个串结束,idx=3.同时cnt[3]++,代表3号节点是某个单词的末尾节点
存入abd,son[0][0]已经存在了,检索b,也就是son[1][1],存在,然后检索son[2]3未创建,则让son[2][3]=++idx,也就是4号节点
如图
如图,虚线是没有填充的字母儿子们。可见,trie树空间浪费非常严重,属于空间换时间
#include<stdio.h>
#define N 10000
//change函数是把输入的范围映射到儿子序号的函数,这里字母a-z代表0-25
int change(char a);
void insert(char *str);
int query(char *str);
int main(){
char a[]="shaniao";
char b[]="feizhu";
insert(a);
insert(b);
insert(a);
printf("%d\n",query(a));
printf("%d\n",query(b));
}
int son[N][26], cnt[N], idx;
int change(char a){
return (int)a-'a';
}
//coding思路:定义p来当id,在for循环内逐个遍历str的字母,change转换字母,查看son是否存在不存在则创建为++idx,然后更新p为儿子id。最后更新cnt
void insert(char *str)
{
int p = 0;
for (int i = 0; str[i]; i ++ ) {
int u = change(str[i]);
if (!son[p][u]) son[p][u] = ++ idx;
p = son[p][u];
}
cnt[p] ++ ;
}
// 查询字符串出现的次数
//思路类似
int query(char *str)
{
int p = 0;
for (int i = 0; str[i]; i ++ ) {
int u =change(str[i]);
if (!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}

浙公网安备 33010602011771号