字典树(Trie)

本文详细介绍前缀树(Trie)的概念、特点及其在字符串处理中的应用。文章首先介绍了前缀树的基本原理,包括其如何利用字符串的公共前缀减少存储空间与查询时间。随后,通过具体的代码示例讲解了前缀树的构建与查询操作,并通过一道典型例题展示了其在实际问题中的运用。

介绍

  • 在计算机科学中,Trie又称前缀树或字典树
  • 是一种针对字符串进行维护的非常高效的数据结构
  • 最大优点是利用字符串的公共前缀来减少存储空间与查询时间
  • 应用于统计、排序和保存大量的字符串(但不仅限于字符串)

例如有 abcd ab abce caa caad 五个字符串,构建字典树如下:
在这里插入图片描述
其中红色表示到当前节点时读取到了一个已存在的字符串
字典树有两种基本操作分别是建树和查询

  • 建树:把一个目标加入到字典树里
  • 查询:查询给定目标在字典树上的属性(是否存在、数量等等)

建树(插入)

假如目标是字符串,且只有小写字母,那么这个树的深度会由字符串而定,广度最大为26
可以开二维数组 trie[N][26] 代表节点,每个节点的值为下一个节点的位置,然后通过深度迭代向里面尝试加入字符串
ind 表示已经使用的最后一个节点,cnt[i] 表示第 i 个节点储存目标的数量
那么插入代码:

void add(string &a){
    int p=0;
    for(int i=0;a[i];i++){
        int t=a[i]-'a';
        if(!trie[p][t])trie[p][t]=++ind;
        p=trie[p][t];
    }
    cnt[p]++;
}

查询

查询操作和插入操作的类似,在字典树根节点按深度向下迭代,对于需要查询的字符串的当前字符,如果这个节点的下一个节点为空,就说明不含这个单词,直接跳出即可
当迭代完成之后,返回 cnt[p]
注意,如果不是求数量而是求目标存不存在,不能直接返回,假如字典中保存了一个字符串 huzai ,而查询的是 hua ,它可以迭代到最后,但是它并不是字典中的字符串,即,需要考虑字典中字符串子串的情况
查询代码:

int query(string &a){
    int p=0;
    for(int i=0;a[i];i++){
        int t=a[i]-'a';
        if(!trie[p][t])return 0;
        p=trie[p][t];
    }
    return cnt[p];
}

经典例题

Trie字符串统计

题目描述

维护一个字符串集合,支持两种操作:

I x 向集合中插入一个字符串 xx;
Q x 询问一个字符串在集合中出现了多少次。

共有 N 个操作,输入的字符串总长度不超过 1e5,字符串仅包含小写英文字母。

输入格式

第一行包含整数 N,表示操作数。
接下来 N 行,每行包含一个操作指令,指令为 I x 或 Q x 中的一种。

输出格式

对于每个询问指令 Q x,都要输出一个整数作为结果,表示 xx 在集合中出现的次数。
每个结果占一行。数据范围1≤N≤2e4

样例

输入

5
I abc
Q abc
Q ab
I ab
Q ab

输出

1
0
1

解题代码

#include<iostream>
using namespace std;
const int N=1e6+7;

int n;
int trie[N][26],cnt[N],ind;

void add(string &a){
	int p=0;
	for(int i=0;a[i];i++){
		int t=a[i]-'a';
		if(!trie[p][t])trie[p][t]=++ind;
		p=trie[p][t];
	}
	cnt[p]++;
}
int query(string &a){
	int p=0;
	for(int i=0;a[i];i++){
		int t=a[i]-'a';
		if(!trie[p][t])return 0;
		p=trie[p][t];
	}
	return cnt[p];
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n;
	string op,s;
	while(n--){
		cin>>op>>s;
		if(op=="I")add(s);
		else cout<<query(s)<<endl;;
	}
	return 0;
}
评论 15
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花崽oyf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值