数据结构——Trie树

介绍

Trie树主要是用来存储和查找字符串的,也叫作字典树,它是一种以空间换时间的数据结构。它的本质就是把多个字符串的公共前缀保存到一起,利用这这种数据结构可以很高效地进行存储和查找操作了。

案例

拿一个例子来说吧,比如说下面这幅图:

插入“abcd”,“abcc”,“abda”,“bcdc”,“bcda”,“bcdd”,“bcd”这几个字符串,它的步骤是这样的:

  1. 创建数组son[ ] [ ] , 遍历每个字符串,每个字符串一个字符一个字符遍历

  2. 查询son[0]这一行有没有第一个字符,如果没有,就保存下来,如果没有,son就进入下一行,继续遍历下一个字符

  3. 一直直到查询到末尾,然后给这个末尾这个地方打一个标记,表示有这么一个字符串

查询操作跟上面的像,步骤:

  1. 在son数组中从第一个字符开始查询,如果有匹配的,就继续向下查询,如果没有,就直接返回0,表示不存在

  2. 当查询到最后,说明存在,返回已经插入的该字符串的数目

题目:

下面拿一道题目来说:

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

  1. I x 向集合中插入一个字符串 xx;

  2. Q x 询问一个字符串在集合中出现了多少次。

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

输入格式

第一行包含整数 N,表示操作数。

接下来 N 行,每行包含一个操作指令,指令为 I xQ x 中的一种。

输出格式

对于每个询问指令 Q x,都要输出一个整数作为结果,表示 x 在集合中出现的次数。

每个结果占一行。

数据范围

1≤N≤2∗10^4

输入样例:

5 I abc Q abc Q ab I ab Q ab

输出样例:

1 0 1

分析:

数据范围在10^4,所以我们可以创建常量 N = 100010,这道题目说了字符串仅包含小写英文字符,所以可以创建一个int类型的数组son[ N] [ 26 ]来保存字符,用cnt[N]来保存某个字符串插入的数目,还要用一个变量idx来设置保存进son数组中的值,因为只有这样才能找到下一行该去的地方,具体的可以见下面的代码

代码:

#include<iostream>
using namespace std;
​
const int N = 100010;
int son[N][26]; //这个数组使用了存储字符串的
int cnt[N]; // 这个数组是用来保存某个字符串出现的次数的
int idx; // 下标是0的点,既是根节点,也是空节点,每当son数组中要存储字符的时候,保存idx
char str[N];
​
void insert(string str){
  int p = 0;
  for(int i = 0; str[i]; i++){
    int u = str[i] - 'a'; // 将 a ~ z 映射为 0 ~ 25
    if(!son[p][u]) son[p][u] = ++idx; // 如果在第p排的第u个位置上没有存储,就把idx存储
    p = son[p][u]; // 让p继续向后走
  }
  cnt[p]++;
}
​
int query(string str){
  int p = 0;
  for(int i = 0; str[i]; i++){
    int u = str[i] - 'a';
    if(!son[p][u]) return 0; // 如果son[p][u]为空,说明不存在该字符串,返回0
    p = son[p][u];
  }
  return cnt[p]; // 所有的字符串都在cnt数组中存储,比如说存储了“abcdef”,没有存储“abcd”,你查找“abcd”是找不到的,每当存储一个字符串都会在末尾打个标记表示存了这么一个字符串
}
​
int main(){
  int n;
  cin >> n;
  while(n--){
    char op;
    cin >> op >> str;
    if(op == 'I') insert(str);
    else cout << query(str) << endl;
  }
  return 0;
}

 

以上就是本次介绍的Trie数了,如果有错误或者不足欢迎指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值