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 ...
随机推荐
- CSP2019 退役记
本来想写"退役在即"的,考完 Day2 后直接改成"退役记"了 Day 0 在 ssf 的机房里继续变弱,自己写了一遍 splay 板子,居然写对了,开心 非常 ...
- [唐胡璐]Selenium技巧- IEDriverServer在进程中没有关闭?
有时候跑完脚本后,IEDriverServer.exe进程没杀掉。 解决方法: 在关闭driver时用Driver.Quit();不要用Driver.Close();Driver.Quit() Qui ...
- css3 制作圆环进度条
引子 移动端做一个 loadiing 加载的图标,跟以往沿用的都不太一样,是一个圆环进度条,圆环进度条也就罢了,还得能用百分比控制. CSS3 实现圆环 demo 刚开始写这个圆环的时候是参照帖子上给 ...
- Linq 分组查询
根据部门分组 ,然后存储部门下所有员工 public class Custom { public string dname { get; set; } public List<Employees ...
- Qt 程序自动重启的实现
正常退出调用exit() 或quit()就行,想要自已重启可按下面代码: void XXX:onRestart() { //类中调用 qApp->exit(); } 主main函数中处理 int ...
- Codeforces Round #589 (Div. 2) C - Primes and Multiplication(数学, 质数)
链接: https://codeforces.com/contest/1228/problem/C 题意: Let's introduce some definitions that will be ...
- SQL Update多表联合更新的方法
SQL Update多表联合更新的方法 (1) sqlite 多表更新方法 update t1 set col1=t2.col1 from table1 t1 inner join table2 t2 ...
- luogu P1494 [国家集训队]小Z的袜子 ( 普 通 )
题目: 链接:https://www.luogu.org/problemnew/show/P1494 题意:一些袜子排成一排,每个袜子有固定的颜色. ...
- django-配置相关
1 自己配置一个静态文件夹 settings.py中 # 用户上传的文件配置 MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'me ...
- Centos7安装Redis5.0.3
1.切换目录 cd tmp 2.下载 wget http://download.redis.io/releases/redis-5.0.3.tar.gz 3.解压,删除压缩包 tar xzf redi ...