Trie代码学习
感觉不把这个Trie理解一下,AC自动机的代码看起来有点费劲。
这里代码的学习仿照训练指南209页。
这里如果只是查询单词,感觉用map更好,但是如果查前缀,还是用Trie。
1、Trie查询前缀字符串是否存在。
- #include <bits/stdc++.h>
- using namespace std;
- #define mst(s,v) memset(s, v, sizeof(s));
- const int maxnode = ;
- const int sigma_size = ;
- //字母表为全体小写字母的Trie
- struct Trie{
- int ch[maxnode][sigma_size];
- int val[maxnode];
- int sz; //结点总数
- Trie(){ sz=; mst(ch[], ); mst(val, ); } //初始时只有一个根节点
- int idx(char c) { return c-'a'; }
- //插入字符串s,附加信息为v。v!=0(0代表本身不是单词结点)
- void insert(char *s, int v){
- int u = , n = strlen(s);
- for(int i=; i<n; i++){
- int c = idx(s[i]);
- if(!ch[u][c]){ //结点不存在
- memset(ch[sz], , sizeof(ch[sz]));
- val[sz] = ; //中间结点的附加信息为0
- ch[u][c] = sz++;
- }
- u = ch[u][c];
- }
- val[u] = v; //字符串的最后一个字符的附加信息
- //标记在末结点,查询整个单词时有用
- }
- bool find(char *s){
- int u = , len = strlen(s);
- for(int i=; i<len; i++){
- int c = idx(s[i]);
- if(!ch[u][c]) return false;
- u = ch[u][c];
- }
- return true; //查询整个单词时 return val[u]
- }
- }tree;
- int main(){
- freopen("in.txt", "r", stdin);
- int n, m;
- cin >> n >> m;
- char tmp[];
- for(int i=; i<n; i++){
- cin >> tmp;
- cout << tmp << endl;
- tree.insert(tmp, );
- }
- for(int i=; i<m; i++){
- cin >> tmp;
- cout << endl << tmp << endl;
- if(tree.find(tmp)) cout << "Y" << endl;
- else cout << "N" << endl;
- }
- return ;
- }
- /*
- 6 2
- shex
- shexy
- yasherhs
- say
- shrxy
- sher
- yasherhs
- she
- */
2、Trie查询前缀个数
- #include <bits/stdc++.h>
- using namespace std;
- #define mst(s,v) memset(s, v, sizeof(s));
- const int maxnode = ;
- const int sigma_size = ;
- //可以查找前缀,也可以查找单词(map)
- struct Trie{
- int ch[maxnode][sigma_size];
- int sum[maxnode];
- int sz; //结点总数
- Trie(){ sz=; mst(ch[], ); mst(sum, ); }
- int idx(char c) { return c-'a'; }
- //插入字符串s,附加信息为v。v!=0(0代表本身不是单词结点)
- void insert(char *s){
- int u = , n = strlen(s);
- for(int i=; i<n; i++){
- int c = idx(s[i]);
- if(!ch[u][c]){ //结点不存在
- memset(ch[sz], , sizeof(ch[sz]));
- ch[u][c] = sz++;
- }
- sum[ch[u][c]]++;
- u = ch[u][c];
- }
- }
- int find(char *s){
- int u = , len = strlen(s);
- for(int i=; i<len; i++){
- int c = idx(s[i]);
- if(!ch[u][c]) return ;
- u = ch[u][c];
- }
- return sum[u];
- }
- }tree;
- int main(){
- freopen("in.txt", "r", stdin);
- int n, m;
- cin >> n >> m;
- char tmp[];
- for(int i=; i<n; i++){
- cin >> tmp;
- tree.insert(tmp);
- }
- for(int i=; i<m; i++){
- cin >> tmp;
- cout << tmp << endl;
- cout << tree.find(tmp) << endl;
- }
- return ;
- }
3、用指针理解Trie
- #include <bits/stdc++.h>
- using namespace std;
- #define mst(s,v) memset(s, v, sizeof(s));
- const int sigma_size = ;
- struct node{
- int count;
- node * next[];
- }*root;
- int idx(char c){ return c-'a'; }
- node* build(){
- node* k = new(node);
- k->count = ;
- mst(k->next , );
- return k;
- }
- void insert(char* s){
- node* r = root;
- char* word = s;
- while(*word){
- int c = idx(*word);
- if(r->next[c] == NULL) r->next[c] = build();
- r = r->next[c];
- r->count++;
- word++;
- }
- }
- int find(char* s){
- node* r = root;
- char* word = s;
- while(*word){
- int c = idx(*word);
- r = r->next[c];
- if(r==NULL) return ;
- word++;
- }
- return r->count;
- }
- int main(){
- freopen("in.txt", "r", stdin);
- int n, m;
- cin >> n >> m;
- char tmp[];
- root = build();
- for(int i=; i<n; i++){
- cin >> tmp;
- insert(tmp);
- }
- for(int i=; i<m; i++){
- cin >> tmp;
- cout << tmp << endl;
- cout << find(tmp) << endl;
- }
- return ;
- }
Trie灵活的地方是在插入时对点的属性的更新,以及查询时与其他算法的结合。
这里将AC自动机summer-work那里的C - L语言拿过来,感受在查询变化的一些思路。
题意:n(1,20)模式串(可以有包含关系(这就决定了不能贪心)),m(1,20)文本串,对每个文本串,n个模式串最多可以组成的最长前缀的位置。
这题就是在find()上思考解法,正解应该是dp[i]是否能理解前i个单词,这里因为是学习Trie,所以就暴力吧(感觉自己太水)。
这里总结一个套路,因为是单词而非前缀,所以insert()时点的属性是val=1。
为了创造vis(是否理解前i个单词)的边界条件vis[0]=v(明显可以识别),所以这里scanf(s+1),即遍历时从i+1开始。
- #include <bits/stdc++.h>
- using namespace std;
- #define mst(s,v) memset(s, v, sizeof(s));
- const int maxnode = ;
- const int sigma_size = ;
- const int maxlen = 1e6 + 5e4;
- int dp[maxlen];
- struct Trie{
- int ch[maxnode][sigma_size];
- int val[maxlen];
- int sz;
- Trie(){ sz=; }
- inline int idx(char c) { return c-'a'; }
- inline void insert(char *s){
- int u = , n = strlen(s);
- for(int i=; i<n; i++){
- int c = idx(s[i]);
- if(!ch[u][c]){
- ch[u][c] = sz++;
- }
- u = ch[u][c];
- }
- val[u] = ; //标记单词
- }
- inline int find(char *s, int v){
- int u = , len = strlen(s), ans = ;
- dp[] = v; //标记能够被识别的前缀位置
- for(int i=; i<len; i++){
- if(dp[i] == v){
- u = ;
- for(int j=i+; j<len; j++){
- int c = idx(s[j]);
- if(!ch[u][c]) break;
- //cout<<"u = "<<u<<" v = "<<v<<" s[j] = "<<s[j]<<endl;
- u = ch[u][c];
- if(val[u]){ //找到单词的前缀
- ans = max(ans, j);
- dp[j] = v; //标记位置
- }
- }
- }
- }
- return ans;
- }
- }tree;
- char tmp[maxlen];
- int main(){
- // freopen("in.txt", "r", stdin);
- int n, m;
- scanf("%d%d", &n, &m);
- for(int i=; i<n; i++){
- scanf("%s", tmp);
- tree.insert(tmp);
- }
- for(int i=; i<=m; i++){
- scanf("%s", tmp+);
- printf("%d\n", tree.find(tmp, i));
- }
- return ;
- }
Trie代码学习的更多相关文章
- u-boot代码学习内容
前言 u-boot代码庞大,不可能全部细读,只能有选择的读部分代码.在读代码之前,根据韦东山教材,关于代码学习内容和深度做以下预先划定. 一.Makefile.mkconfig.config.mk等 ...
- Objective-C代码学习大纲(3)
Objective-C代码学习大纲(3) 2011-05-11 14:06 佚名 otierney 字号:T | T 本文为台湾出版的<Objective-C学习大纲>的翻译文档,系统介绍 ...
- ORB-SLAM2 论文&代码学习 ——Tracking 线程
本文要点: ORB-SLAM2 Tracking 线程 论文内容介绍 ORB-SLAM2 Tracking 线程 代码结构介绍 写在前面 上一篇文章中我们已经对 ORB-SLAM2 系统有了一个概览性 ...
- ORB-SLAM2 论文&代码学习 —— 单目初始化
转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12358458.html 本文要点: ORB-SLAM2 单目初始化 ...
- ORB-SLAM2 论文&代码学习 —— LocalMapping 线程
转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12360913.html 本文要点: ORB-SLAM2 Local ...
- Learning Memory-guided Normality代码学习笔记
Learning Memory-guided Normality代码学习笔记 记忆模块核心 Memory部分的核心在于以下定义Memory类的部分. class Memory(nn.Module): ...
- 3.1.5 LTP(Linux Test Project)学习(五)-LTP代码学习
3.1.5 LTP(Linux Test Project)学习(五)-LTP代码学习 Hello小崔 华为技术有限公司 Linux内核开发 2 人赞同了该文章 LTP代码学习方法主要介绍两个步骤, ...
- Apollo代码学习(七)—MPC与LQR比较
前言 Apollo中用到了PID.MPC和LQR三种控制器,其中,MPC和LQR控制器在状态方程的形式.状态变量的形式.目标函数的形式等有诸多相似之处,因此结合自己目前了解到的信息,将两者进行一定的比 ...
- Dagger2 生成代码学习
接上一篇文章介绍了Dagger2的初步使用,相信刚接触的人会觉得很奇怪,怎么会有很多自己没有定义的代码出现,为什么Component的创建方式是那样的.为了搞清楚这些东西,我们需要查看一下Dagger ...
随机推荐
- Launcher类源码分析
基于上一次获取系统类加载器这块进行分析: 关于这个方法的javadoc在之前已经阅读过了,不过这里再来仔细阅读一下加深印象: 这里有一个非常重要的概念:上下文类加载器: 它的作用非常之大,在后面会详细 ...
- P1361 小M的作物 最小割理解
如果没有组合效益的存在 我们直接每个点两部分的最大值即可 换成网络流模型来看 即把S点看作是A田 把T点看作是B田 每种作物看作一个点 分别连边(S,i,A[i]) (i,T,B[i]) 最后图中所有 ...
- WebRtc的一些基本概念
GCC:Google Congestion Control,谷歌提出的拥塞控制算法 REMB:Receiver Estimated Maximum Bitrate, 接收端最大接收码率估测,接收端会 ...
- 通过自动回复机器人学Mybatis---基础版
第1章 案例简介 介绍要实现的案例情况,后面会通过这个案例来学习 Mybatis 第2章 实战第一部----黎明前的黑暗 在没有 Mybatis 的情况下,使用 Jsp + Servlet + Jdb ...
- 上传时excel类型accept的MIMI类型
1.excel文件类型 accept='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/v ...
- dcm4che-core导包失败! mvn pom文件导包总是失败
原因可能是所导的包不在共有项目中,可能在个人项目中,需要添加远程仓库 <!--远程仓库部署--><repositories> <repository> <id ...
- STMStudio-stm32软件的应用笔记
上次编写中,已经提到该软件的功能了,可以增加调试手段. 编译出axf文件-keil和out文件-iar,注意keil在output文件名是,不能有"."既NL_ZKTP3_V1.0 ...
- 适配器模式(Adapter)---结构型
1 基础知识 定义:将一个类的接口(被适配者)转换成客户期望的另一个接口(目标).特征:使原本接口不兼容的类可以一起工作. 本质:转换匹配,复用功能.把不兼容的接口转换为客户端期望的样子从而实现功能的 ...
- 解决蓝牙鼠标在 Ubuntu 中单位时间内断开的问题
1 查询你的鼠标的蓝牙地址 1.1 如:E1:DE:02:05:5E:F5 2 将查询到的设备地址写入配置文件 /etc/bluetooth/main.conf # Use vendor id sou ...
- vue中前进刷新、后退缓存用户浏览数据和浏览位置的实践
vue中前进刷新.后退缓存用户浏览数据和浏览位置的实践 2018年07月07日 11:58:40 大灰狼的小绵羊哥哥 阅读数:4492 vue中,我们所要实现的一个场景就是: 1.搜索页面==&g ...