【字符串算法】字典树Trie入门
基本概念
顾名思义,字典树(也叫前缀树)就是可以像字典那样来保存一些单词的集合。
如图所示:
(图片来自OIWiKi)
设根节点的标号为,然后其余结点依次编号;我们用数组来存每个节点的所有子节点
更具体地,设数组,其中表示最大可能的节点个数,是字符集合。表示结点标号为的结点 的 字母编号为(比如说,j=字母-'a')的子节点的结点标号。如果为,则表示没有字母编号为的子节点。
操作-插入
插入的时候,直接从根节点开始遍历,根据要插入的字符串往下面走,如果碰到没有的字符就新插入结点就可以了。
scanf("%s",s+1); //插入字符串 这颗trie根节点是从1开始的 int u=1,len=strlen(s+1); for(int j=1;j<=len;j++) { int c=s[j]-'a'; if(!ch[u][c])//原本没有这个字符 ch[u][c]=++tot;//插入这个字符 u=ch[u][c]; }
操作-查询
查询与操作是相似的,这里不再赘述。
不过要注意,在字典树里面可以查找到的不一定就是单词,还有可能是单词的前缀。
比如说字典树里面有一个单词为,查询时在字典树里面会查到它,但是它只是一个前缀,不是单词。
所以我们还需要再添加一个标记数组表示节点标号为的结点是否为一个单词的结尾,我们把这个节点叫做单词结点。显而易见,我们之前的那个插入就要改一下了。
同样的,这个标记数组还可以干一些别的事情,比如在字符串被附了权值的情况下存这个字符串(以当前结点结尾的字符串)的权值。
scanf("%s",s+1); int u=1,len=strlen(s+1); for(int j=1;j<=len;j++) { int c=s[j]-'a'; u=ch[u][c]; if(!u) break;//不存在 } if(tag[u]==0) ... //不存在
操作-删除
其实直接把单词结点的标记清掉就可以了。
但是呢,也可以针对特殊情况特殊处理一下。
分类讨论一下:
- 那么直接把整个单词全部删掉就可以了。(清
- 如果被删除单词的那条链上某处有了分支,然后那个分支应该是有一支是表示被删除单词的,其他的都不是,那么删掉这一支就可以了(清
其实还是有些麻烦,还不如直接清标记...
例题 & 模板

1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 #define N 500005 8 int ch[N][26];//结点i的为j+'a'子节点的节点标号 9 char s[55]; 10 int n,m,tag[N],tot=1; 11 int main() 12 { 13 scanf("%d",&n); 14 for(int i=1;i<=n;i++) 15 { 16 scanf("%s",s+1); 17 //插入字符串 这颗trie根节点是从1开始的 18 int u=1,len=strlen(s+1); 19 for(int j=1;j<=len;j++) 20 { 21 int c=s[j]-'a'; 22 if(!ch[u][c])//原本没有这个字符 23 ch[u][c]=++tot;//插入这个字符 24 u=ch[u][c]; 25 } 26 tag[u]=1;//标记这个结点是单词结点 27 //--- 28 } 29 scanf("%d",&m); 30 while(m--) 31 { 32 scanf("%s",s+1); 33 int u=1,len=strlen(s+1); 34 for(int j=1;j<=len;j++) 35 { 36 int c=s[j]-'a'; 37 u=ch[u][c]; 38 if(!u) break;//名字不存在 39 } 40 if(tag[u]==1) 41 { 42 puts("OK"); 43 tag[u]=2; 44 } 45 else if(tag[u]==2) 46 puts("REPEAT"); 47 else puts("WRONG"); 48 } 49 return 0; 50 }
后记
做了例题之后,发现干的事情也能干,也能干,不就是存个单词,查个单词嘛!
别急,他还有很多用法...检索字符串只是最基本的操作而已...
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现