Trie树的个人理解与分析
今天是怠惰的一天,基本完全浪费了。想着这样不行啊。。。今天还没打代码呢。so,学了这个trie树。这个应该是很简单的一个数据结构,但是奈何完全不在状态,写个解析用纸代替大脑记忆,后面忘了回来看看(这更像是一个大脑日志?
一、基本介绍
Trie树又称字典树、单词查找树。是一种能够高效存储和查找字符串集合的数据结构。咋看之下不是很复杂,但是仔细看代码又有点模糊。储存形式如下:
二、用数组来模拟Trie树的具体分析
一图解释:
插入操作代码:
void insert(char *str)
{
int p = 0; //类似指针,指向当前节点
for(int i = 0; str[i]; i++)
{
int u = str[i] - 'a'; //将字母转化为数字
if(!son[p][u]) son[p][u] = ++idx;
//该节点不存在,创建节点,其值为下一个节点位置
p = son[p][u]; //使“p指针”指向下一个节点位置
}
cnt[p]++; //结束时的标记,也是记录以此节点结束的字符串个数
}
查找操作代码:
int query(char *str)
{
int p = 0;
for(int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
if(!son[p][u]) return 0; //该节点不存在,即该字符串不存在
p = son[p][u];
}
return cnt[p]; //返回字符串出现的次数
}
三、835完整代码
//Trie树快速存储字符集合和快速查询字符集合
#include <iostream>
using namespace std;
const int N = 100010;
//son[][]存储子节点的位置,分支最多26条;
//cnt[]存储以某节点结尾的字符串个数(同时也起标记作用)
//idx表示当前要插入的节点是第几个,每创建一个节点值+1
int son[N][26], cnt[N], idx;
char str[N];
void insert(char *str)
{
int p = 0; //类似指针,指向当前节点
for(int i = 0; str[i]; i++)
{
int u = str[i] - 'a'; //将字母转化为数字
if(!son[p][u]) son[p][u] = ++idx; //该节点不存在,创建节点
p = son[p][u]; //使“p指针”指向下一个节点
}
cnt[p]++; //结束时的标记,也是记录以此节点结束的字符串个数
}
int query(char *str)
{
int p = 0;
for(int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
if(!son[p][u]) return 0; //该节点不存在,即该字符串不存在
p = son[p][u];
}
return cnt[p]; //返回字符串出现的次数
}
int main()
{
int m;
cin >> m;
while(m--)
{
char op[2];
scanf("%s%s", op, str);
if(*op == 'I') insert(str);
else printf("%d\n", query(str));
}
return 0;
}
四、参考
AcWing算法基础课第二章数据结构(二)
你这篇讲解的最好
有一个地方不太懂,就是比如插入两个不同字符串长度都是N,那插入了第一个之后idx值就到N了,插入第二个字符串时,因为son[p][u]=++idx;和p=son[p][u];这两步p值的变化早晚会使数组越界,那么这时在数组范围外进行插入操作真的不会有问题吗?
看了下网友的回答是输入的所有字符串之和不超过N哈
为什么这里可以不加&啊(scanf(“%s%s”, op, str);)
这个op[2]里边为啥是2啊
*op == ‘I’这个是什么原理啊
1:数组的名字就是数组里第一个元素的地址,不需要再取地址,取地址也可以
2:他是用%s读入的,读入是字符串所以要数组多开一位方便系统补零构成字符串
3:因为数组的名字就是数组里第一个元素的地址,所以对他解引用得到第一个元素i
图一画错了,字符串”abc”的字符’c’应该和字符串”abcd”的字符’c’共用一个节点(即图二/一图解释)。
xdm,这个 scanf(“%s%s”, op, str);为什么读入的是地址啊。直接读入&op,&str,后面传入的时候就不用op和str(用op和str)不行嘛
这个地方是以字符串的形式读入的,具体可以参看下评论区
图画的太棒了
为什么cnt是一维而不是二维
清晰易懂,点了
为什么访问的时候cnt[p]不用++
神中神
加上我刚好100条评论,如下:
写那么明白就该去一楼 :)
tql
idx指已经用到了哪个下标,也是树的结点的编号,用以区分每个结点;cnt指有多少字符串在当前结点结尾;
int u= s[i] - ‘a’ ; 这一步为啥可以映射到0~25?
ASCLL码转换
很清楚
tqltql
大佬好棒
这里的N应该为 节点个数 而不是字符串长度,有大佬解析一下这句话吗,节点个数是指啥,怎么求出来节点有多少个的?ovo
大佬写的很清晰 感谢
tql