自动机入门——字典树(Trie)
字典树定义:字典树,英文名 trie。顾名思义,就是一个像字典一样的树。
我们先看一下字典树的具体结构:
字典树用边来代表字母,从根节点到某一节点的路径代表一个字符串,例如 1-3-7便代表“ba”,结构是十分间接明了的,对于代码而言呢,我们可以定义一个二维数组来表示字典树:t[][];
t[i][j]=k的含义便是编号为i的第j个节点的编号是k。j的含义也就是这个节点向上连的边是哪个字符,原因是我们会将j定义为顺序的数字去表示字符,如用(1,2,3)来表示(a,b,c).
整体的思路便是逐层从左到右依次检查每一个字母是否存在。
具体的插入代码便是:
void insert() {
int len=s.size()-1;
int now=0;//now是根节点
for(int i=0;i<=len;i++) {
int k=s[i]-'a';//k是我们提到的j的编号
if(!t[now][k]) {//如果没有从now到k的前缀,插入
t[now][k]=++cnt;//cnt是插入的编号,cnt初始为0逐步递增
} else {
now=t[now][k];//否则我们将now向下顺着字典树走一层
}
}
}
我们可以看出,如果是全是小写字母的话数组第二位开26便可以了,所有字典树对空间的要求也不算特别大。
而查询代码:
bool search() {
int len=s.size()-1;
int now=0;
for(int i=0;i<=len;i++) {
int k=s[i]-'a';
if(!t[now][k]) return false;//没有找到以now为头的字串,即不存在
now=t[now][k];//找到了顺着字典树找下一个字母
}
return true;
}
字典树的结构十分简单,不过多赘述了,但是注意像字典一样的树 这样的描述事情看起来更像是一个数据结构,但是相对于数据结构来说,似乎将其定义为自动机更好一些,对于后续AC自动机等的理解也更加容易,另外wiki上也是明确表明了字典树属于自动机而并非数据结构。
首先我们看wiki上对自动机的定义:
1.字符集不必多说,字典树本质就是为了处理字符串。
2&&3. 状态表示与起点状态便是树上各个节点及其含义。
重点说4与5。
4. 所谓接受状态,即字典树读入一个字符串从初始状态按照转移函数一个一个字符进行转移中的状态,即是不是可以接受这个字符串(字符),例如新的字符串有没有可能完美映射到字典树上,
如果可以便是可接受状态,否则不可接受,这时候我们便要进行相关操作(建树过程便是开新的节点(令其变为一个可接受状态),查询过程就是返回false)。
5. (4) 中我们也提到了转移函数,那么结合其定义,对于字典树而言,转移函数就是树上的边,边相连的节点是两个参数,是否需要插入(或是否存在)便是返回值。
对于这一部分吧来说,是一个可接受的状态为 aa,ab,ba的自动机,扩展到整个状态便是一个可以检索相关数据的一个数学模型,相对于栈,线段树来说,字典树并没有特别明显的存储数据的特点,比如无法确定一共存储了多少个字符串,不能实现输出所有匹配的字符串的操作。但总归只要理解了字典树,能够ac便是最好的啦。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析