Trie树

作用:高效地存储和查找字符串集合的数据结构

用到Trie树的题字母类型不会很多,一定都会有限制

如想在Trie中存储如下元素:

abcdef,abdef,aced,bcd,bcff,cdaa,bcdc,abc

存储方式如下:

在根节点root后,从头向后遍历,在每个单词的结尾位置做标记,如下图:

那么如何进行高效查找呢?

如现在想去查找aced这个单词,如上图,会从root开始走,先走a,再走c,再走e,再走d,发现d上有红色结束标记,说明存在aced

如现在如查找abk,会先从root走到a,再走b,发现不存在c,那么abc就不存在。

1.1 练手题目

1.2 练手答案

#include<iostream>

using namespace std;

const int N = 100010;

int son[N][26]; // 因为题目说26个英文小写字母,所以子节点最多只有26
int cnt[N]; // 存储以当前这个点结尾的有多少个
int idx; // 当前用到了哪个下标,下标是0的点既是根节点又是空节点
char str[N];

void insert(char str[])
{
    int p = 0;
    // C++中字符串结尾是'\0'所以可以str[i]判断
    for(int i = 0; str[i]; i++)
    {
        int u = str[i] - 'a'; // 把字母映射成0-25

        // 使用idx是为了区分方便,因为可能同时并列存在多个字符'a'
        // idx是全局变量一直没重置
        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 = str[i] - 'a';
        if(!son[p][u]) return 0; //不存在
        p = son[p][u];
    }
    return cnt[p]; // 返回以p结尾的单词数量
}

int main()
{
    int n;
    cin >> n;
    while(n--)
    {
        char op[2];
        cin >> op >> str;
        if(op[0] == 'I') insert(str);
        else cout << query(str),puts("");
    }
    cout << "idx=" << idx;
    return 0;
}
posted @ 2021-03-26 10:10  晓尘  阅读(56)  评论(0)    收藏  举报