算法学习笔记(17)——Trie

Trie

Trie(字典树)是一种用于实现字符串快速检索的多叉树结构。Trie 的每个节点都拥有若干个字符指针,若在插入或检索字符串时扫描到一个字符 c ,就沿着当前节点的 c 字符指针,走向该指针指向的节点。下面详细讨论 Trie 的基本操作过程:

  • 初始化:一棵空 Trie 仅包含一个根结点,该点的字符指针均指向空。
  • 插入:当需要插入一个字符串 S 时,我们令一个指针 P 起初指向根节点。然后,依次扫描 S 中的每个字符 c。
    1. 若 P 的 c 字符指针指向一个已经存在的节点 Q,则令 P=Q。
    2. 若 P 的 c 字符指针指向空,则新建一个节点 Q,令 P 的 c 字符指针指向 Q,然后令 P=Q。
    3. 当 S 中的字符扫描完毕时,在当前节点 P 上标记它是一个字符串的末尾。
  • 检索:当需要检索一个字符串 S 在 Trie 中是否存在时,我们令一个指针 P 起初指向根结点,然后依次扫描 S 中的每个字符 c:
    1. 若 P 的 c 字符指针指向空,则说明 S 没有插入过 Trie,结束检索。
    2. 若 P 的 c 字符指针指向一个已经存在的节点 Q,则令 P=Q。
    3. 当 S 中的字符扫描完毕时,若当前节点 P 被标记为一个字符串的末尾,则说明 S 在 Trie 中存在,否则说明 S 没有被插入过 Trie。

img

题目链接:AcWing 835. Trie字符串统计

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int n;
char str[N];    // 保存待操作的字符串
int son[N][26]; // 二维数组模拟Trie树,每个节点有26个子节点,对应26个字母
int cnt[N];     // 保存以某编号节点结尾的字符串数量
int idx;        // 保存节点的编号

void insert(char *str)
{
    // 初始字符指针指向根节点
    int p = 0;
    // 依次扫描str中的每个字符
    for (int i = 0; str[i]; i ++ ) {
        // 将英文字母转换为0~26的整数
        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;
    // 依次扫描str中的每个字符
    for (int i = 0; str[i]; i ++ ) {
        // 将英文字母转换为0~26的整数
        int u = str[i] - 'a';
        // 如果该字符不存在,则代表没有插入过这个字符串,返回数量0
        if (!son[p][u]) return 0;
        // 将字符指针指向新检索到的字符
        p = son[p][u];
    }
    // 返回以p指针指向的字符结尾的字符串数量
    return cnt[p];
}

int main()
{
    cin >> n;
    
    while (n -- ) {
        char op[2];
        scanf("%s%s", op, str);
        if (*op == 'I') insert(str);
        else printf("%d\n", query(str));
    }
    
    return 0;
}
posted @ 2022-12-09 22:07  S!no  阅读(25)  评论(0编辑  收藏  举报