当前位置: 首页 > article >正文

Trie(算法版)

#include <iostream>

using namespace std;

const int N=100010;
int son[N][26],cnt[N],idx;
//son记录trie数,cnt记录每个词出现的次数,idx记录每个字符所占⽤的下标

//加入字符串
void add(char str[]){
	//idx = 0既表⽰根节点也表⽰空节点
	int p =0;
	for(int i =0;str[i];i++){  //字符串末尾为0
		int u = str[i]-'a';
		if(!son[p][u]){
			son[p][u]= ++idx;//当前字符不存在,增加
		}
		p=son[p][u];  //向下继续遍历
	}
	cnt[p]++;  //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];
	}
	return cnt[p];  //p指向字符串的最后一个字符
}

int main(){
	int n;
	cin>>n;
	while(n--){
		char op;
		char x[N];
		cin>>op>>x;
		if(op=='I')add(x);
		else cout<<query(x)<<endl;
	}

	return 0;

}

假设情境 1096:我们有一个 Trie 树,开始时是空的。我们现在要插入以下两个单词:cat 和 car。

 

初始状态:

 
  • idx:初始值为 0,表示根节点。
  • son [N][26]:所有元素初始值为 0,表示 Trie 树是空的。
 

插入 “cat”:

 
  1. 字符 'c':
    • 计算索引 u = 'c' - 'a' = 2。
    • 检查 son [0][2],因为 Trie 树是空的,所以 son [0][2] 为 0。由于 son [0][2] 为 0,意味着当前节点 0 没有对应字符 'c' 的子节点。因此,我们创建一个新节点 1,并将 son [0][2] 设为 1,表示根节点 0 的 'c' 子节点是节点 1。
    • 然后,将 p 更新为 1,即移动到节点 1。
    • idx 增加到 1。
  2. 字符 'a':
    • 计算索引 u = 'a' - 'a' = 0。
    • 检查 son [1][0],此时 son [1][0] 仍为 0,因为之前还没有插入任何以 'a' 为第二个字符的单词。
    • 因此,我们创建一个新节点 2,并将 son [1][0] 设为 2。
    • 将 p 更新为 2,现在指向节点 2。
    • idx 增加到 2。
  3. 字符 't':
    • 计算索引 u = 't' - 'a' = 19。
    • 检查 son [2][19],此时 son [2][19] 为 0,因为还没有插入任何以 't' 为第三个字符的单词。
    • 创建新节点 3,并将 son [2][19] 设为 3。
    • p 更新为 3,现在指向节点 3。
    • idx 增加到 3。
    • 此时,已成功插入 “cat”。p 当前指向节点 3,在 cnt [3] 上加 1,表示有一个单词以 't' 结尾。
 

再插入 “car”:

 
  1. 字符 'c':
    • 计算索引 u = 'c' - 'a' = 2。
    • 检查 son [0][2],此时 son [0][2] 为 1,表示根节点已经有一个 'c' 子节点,指向节点 1。
    • 直接将 p 更新为 1,不用创建新节点。
  2. 字符 'a':
    • 计算索引 u = 'a' - 'a' = 0。
    • 检查 son [1][0],此时 son [1][0] 为 2,表示节点 1 有一个 'a' 子节点,指向节点 2。
    • 将 p 更新为 2。
  3. 字符 'r':
    • 计算索引 u = 'r' - 'a' = 17。
    • 检查 son [2][17],此时 son [2][17] 为 0,因为还没有插入任何以 'r' 为第三个字符的单词。
    • 创建新节点 4,并将 son [2][17] 设为 4。
    • p 更新为 4。
    • idx 增加到 4。
    • 现在已成功插入 “car”。p 当前指向节点 4,在 cnt [4] 上加 1,表示有一个单词以 'r' 结尾。
 

总结:
每当我们遇到一个新的字符且当前节点没有对应的子节点时(即 son [p][u] 为 0),我们就需要创建一个新的节点,并更新 son [p][u] 为新节点的编号。同时,idx 自增,用于分配新节点的编号。通过这种方式,Trie 树可以动态地构建,插入和查询操作都能高效完成。


http://www.kler.cn/a/508886.html

相关文章:

  • MySQL(高级特性篇) 06 章——索引的数据结构
  • 记录一次 centos 启动失败
  • ZooKeeper 核心概念与机制深度解析
  • Jira中bug的流转流程
  • Python股票量化交易分析-开发属于自己的指标
  • Java设计模式——单例模式(特性、各种实现、懒汉式、饿汉式、内部类实现、枚举方式、双重校验+锁)
  • Vim 项目的现状
  • Leetcode3287:求出数组中最大序列值
  • 《内网穿透:网络拓展与安全防护的平衡艺术》
  • kubernetes学习-Service(七)
  • 浅谈云计算17 | 分布式存储
  • 【Linux】【Vim】vim编辑器的用法
  • 协同过滤:推荐系统的核心算法详解
  • 会话_JSP_过滤器_监听器_Ajax
  • SimpleHelp远程管理软件存在任意文件读取漏洞(CVE-2024-57727)
  • [STM32 HAL库]串口空闲中断+DMA接收不定长数据
  • 【Pandas】pandas Series apply
  • 电机驱动-标准库和HAL库
  • 分析示例 | Adams_Controls变拓扑分析
  • 【专题一 递归】24. 两两交换链表中的节点
  • 【机器学习:二十六、决策树】
  • 【认识油管头部频道】ep3 “PewDiePie”——游戏内容
  • (RAG系列) FastGPT工作流的http请求模块使用
  • AWS Lambda
  • 【机器学习】鲁棒(健壮)回归-RANSAC(Random Sample Consensus)算法
  • 循环神经网络RNN-数据流动