C++ &数据结构 &Trie树&字典树 (trie字符串统计)

Trie树

定义

又称单词查找树,字典树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

基本性质
  1. 根节点不包含字符,除根节点以外每个节点只包含一个字符。
  2. 从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。
  3. 每个节点的所有子节点包含的字符串不相同。
例图

该trie树存放了at,bee,ben,bt,q五个字符串。
在这里插入图片描述
该trie存放了abcd,abd,bcd,efg,hij五个字符串。
在这里插入图片描述

插入与查询实现方法
插入字典项目的方法为:

(1) 从根结点出发;
(2) 定义关键字第一个字符的值,查找是否存在该子树;
(3) 存在该子树的话就继续查找下一个字符;
(4) 迭代过程……
(5) 最后一个字符插入trie树,标记结束字符(数量加一)。

查询字典项目的方法为:

(1) 从根结点开始一次搜索;
(2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;
(3) 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。
(4) 迭代过程……
(5)如过某节点不存在或不存在下一个字母的子树,说明不存在该关键词。
(6) 如果在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。

题目

题目来源=》AcWing第835题:
维护一个字符串集合,支持两种操作:
I x 向集合中插入一个字符串 x;
Q x 询问一个字符串在集合中出现了多少次。
共有 N 个操作,输入的字符串总长度不超过 105,字符串仅包含小写英文字母。
输入格式
第一行包含整数 N,表示操作数。
接下来 N 行,每行包含一个操作指令,指令为 I x 或 Q x 中的一种。
输出格式
对于每个询问指令 Q x,都要输出一个整数作为结果,表示 x 在集合中出现的次数。
每个结果占一行。
数据范围
1≤N≤2∗104
输入样例:
5
I abc
Q abc
Q ab
I ab
Q ab
输出样例:
1
0
1

题目代码(含详细注释)

//trie树
#include <iostream>
using namespace std;

const int N = 100010;
//son[N][26]存放各个字符
//cnt[N]标记该节点是否为最后一位如果是就代表该字符串的数量
//idx表示节点下标,也代表trie数的结点数
int son[N][26], cnt[N], idx;  
char str[N]; //存放需要操作的字符串

void insert(char *str)
{ // 字符串插入trie树
    int p = 0;  //根节点为0
    for (int i = 0; str[i]; i ++ )
    {
        int u = str[i] - 'a';  //当前字母对应的数字(用int型数字代替小写字母)
        if (!son[p][u]) son[p][u] = ++ idx; //如果该节点不存在就生成一个节点,此时的p为父节点
        p = son[p][u]; //节点值代表当前节点是第几个生成的节点
    }
    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; //如果不存在该节点直接返回 0 ,说明该字符串不存在
        p = son[p][u]; // 节点值为子节点的[p]值
    }
    return cnt[p];
}

int main()
{
    int n;
    scanf("%d", &n);
    while (n -- )
    {
        char op[2];
        scanf("%s%s", op, str);
        if (*op == 'I') insert(str);
        else printf("%d\n", query(str));
    }

    return 0;
}

另外哈希表也可以解题:

#include <iostream>
#include <cstring>
#include <unordered_map>

using namespace std;

unordered_map<string,int> mp;

int main(){
    int n;
    cin >> n;
    while(n -- ){
        char op;
        string x;
        cin >> op;
        if(op == 'I'){
            cin >> x;
            mp[x]++;
        }
        if(op == 'Q'){
            cin >> x;
            cout << mp[x] << endl;
        }
    }
    return 0;
}

trie树查找时间是O(L)L是字符串长度,而hash是O(LL),LL是关键字对应哈希地址链表长度,都和数据的大小无关,查找都很高效,当时再这题显然tried树的时间复杂度会更低。

结语

(定义啥的百度上找来的,本蒟蒻还不是很理解,希望大佬们多多指教!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

叁玖27

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

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

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

打赏作者

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

抵扣说明:

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

余额充值