Trie树的数组实现原理
Trie(Retrieval Tree)又称前缀树,可以用来保存多个字符串,并且非常便于查找。在trie中查找一个字符串的时间只取决于组成该串的字符数,与树的节点数无关。因此,它的查找速度通常比二叉搜索树更快。trie的结构很简单,每条边表示一个字符,从根节点到叶节点就可以表示一个完整的字符串。所以,如果用trie表示一组英文单词,就是一颗26叉数;表示一组自然数,就是一颗10叉树。直观上,实现trie很简单,比如实现英文单词的trie,使用如下的节点构造树:
:::c
struct node
{
char chr;
struct node *edges[26];
};
这样做虽然简单,但没有很好的利用内存,edges数组肯定很多都是闲置的,如果使用到更多字符的话,这种浪费会更严重。这里介绍一种基于数组结构的trie实现方式,不仅节省内存,而且查询速度更快。基于数组查表的时间复杂度为O(|P|),基于平衡树的时间复杂度为O(|P|log|Σ|),其中,P表示查询的字符串长度,Σ表示字符集合。
基于数组的实现方式,把trie看作一个DFA,树的每个节点对应一个DFA状态,每条从父节点指向子节点的有向边对应一个DFA变换。遍历从根节点开始,字符串的每个字符作为输入用来确定下一个状态,直到叶节点。

三数组trie
trie可以用三个数组来表示:
base: 其中的每个元素对应trie上的一个节点,即DFA的状态。对于节点s,base[s]是next和check在状态转换表中的起始位置。如果base[i]为负值或没有next转换,表示该状态为一个词语。next: 和check搭配使用,提供数据池分配稀疏向量,用于保存trie状态转换表的各行数据。来自各个节点的转换向量保存在此数组中。check: 与next平行使用,它与next相同位置的元素记录了next中对应元素的拥有者,即之前的状态。
所谓trie*状态转换表,即状态转换矩阵,是DFA里的概念:横行是状态转换向量*,比如,状态s接受n种输入字符c1,...,cn,即构成状态s的状态转换向量;纵列是各种状态,即trie的各节点。
对于输入字符c,从状态s转换到t,用三数组trie可以表示为:
check[base[s]+c] = s
next[base[s]+c] = t
类似下图:
遍历树
对于给定状态s和输入字符c的遍历算法表示如下:
t := base[s]+c
if check[t] = s then
next state := next[t]
else
fail
endif
创建树
当插入一个状态转换,比如,输入字符c,状态从s转换到t,此时,数组元素next[base[s]+c]]应该是空的,否则,整个占用该数组元素位置的状态转换向量或者状态s的状态转换向量必须要重新迁移(relocate)。实际过程中选择代价较小的那个。假设迁移状态s的状态转换向量,重新分配的起始位置为b,整个过程很简单:
Relocate(s: 状态, b: next数组中新的起始位置)
begin
foreach 状态s后的每种输入字符c
begin
check[b+c] := s 标记前件状态
next[b+c] := next[base[s]+c] 复制原先的状态数据
check[base[s]+c] := none 释放原先的状态数据
end
base[s] := b 完成迁移
end
新位置b的选择比较关键,应该避免迁移过程中再次发生冲突。整个过程如下图,实线表示迁移前,虚线表示迁移后:
双数组trie
三数组trie的next和check数组元素之间存在间隙,可以将base和next合并,把base数组中的表示穿插在next中进行,而next中有值的项直接表示为base的内容,这样就得到两个平行的数组base和check,即双数组trie。
对于输入字符c,从状态s转换到t,用双数组trie可以表示为:
check[base[s]+c] = s
base[s]+c =t
类似下图
遍历
对于给定状态s和输入字符c的遍历算法表示如下:
t := base[s] + c;
if check[t] = s then
next state := t
else
fail
endif
创建树
双数组trie的创建类似三数组trie,但重新迁移方法略有不同:
Relocate(s: 状态, s: base数组中的起始位置)
begin
foreach 状态s后的每种输入字符c
begin
check[b+c] := s 标记前件状态
base[b+c] := base[base[s}+c] 复制原先的状态数据
foreach 状态base[s]+c后的每种输入字符d
begin
check[base[base[s]+c]+d] := b+c
end
check[base[s]+c] := none 释放原先的状态数据
end
base[s] := b 完成迁移
end
整个过程如下图:

参考
http://blog.jqian.net/post/trie.html
Trie树的数组实现原理的更多相关文章
- Wannafly挑战赛10F-小H和遗迹【Trie,树状数组】
正题 题目链接:https://ac.nowcoder.com/acm/contest/72/F 题目大意 \(n\)个字符串,包括小写字母和\(\#\).其中\(\#\)可以替换为任意字符串.求有多 ...
- 字典树(Trie树)的实现及应用
>>字典树的概念 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树.与二叉查找树不同,Trie树的 ...
- Day2:T4求逆序对(树状数组+归并排序)
T4: 求逆序对 A[I]为前缀和 推导 (A[J]-A[I])/(J-I)>=M A[j]-A[I]>=M(J-I) A[J]-M*J>=A[I]-M*I 设B[]=A[]-M*( ...
- bzoj4785 [Zjoi2017]树状数组
Description 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进 ...
- ST表与树状数组
ST表 st表可以解决区间最值的问题.可以做到O(nlogn)预处理 ,O(1)查询,但是不支持修改. st表的大概思路就是用st[i][j]来表示从i开始的2的j次方个树中的最值,查询时就从左端点 ...
- 【BZOJ】3173: [Tjoi2013]最长上升子序列(树状数组)
[题意]给定ai,将1~n从小到大插入到第ai个数字之后,求每次插入后的LIS长度. [算法]树状数组||平衡树 [题解] 这是树状数组的一个用法:O(n log n)寻找前缀和为k的最小位置.(当数 ...
- HDU_2642_二维树状数组
Stars Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/65536 K (Java/Others)Total Submi ...
- 洛谷 P4396 (离散化+莫队+树状数组)
### 洛谷P4396 题目链接 ### 题目大意: 有 n 个整数组成的数组,m 次询问,每次询问中有四个参数 l ,r,a,b .问你在[l,r] 的区间内的所有数中,值属于[a,b] 的数的个 ...
- 树状数组的理解(前缀和 and 差分)
二更—— 有神仙反映数星星那个题外链炸了,我决定把图给你们粘一下,汉语翻译的话在一本通提高篇的树状数组那一章里有,同时也修改了一些汉语语法的错误 这段时间学了线段树组,当神仙们都在学kmp和hash的 ...
随机推荐
- 为什么CNN能自动提取图像特征
1.介绍 在大部分传统机器学习场景里,我们先经过特征工程等方法得到特征表示,然后选用一个机器学习算法进行训练.在训练过程中,表示事物的特征是固定的. 后来嘛,后来深度学习就崛起了.深度学习对外推荐自己 ...
- 改变dos的编码方式
chcp 936 改变成 gbk chcp 65001 改成 utf-8 删除MySqlite文件 generic_x86:/data/data/com.example.lifen.sqlite/da ...
- python之初接触
编程语言相关 1什么是编程语言 编程语言即语言,语言的本质就是沟通,因而编程语言与英语 .法语.日语等所有语言并无区别,只不过英语是人与人之间沟通的介质,而编程语言则是程序员与计算机沟通的介质. 程序 ...
- Jenkins2.0中的pipeline
jenkins的实现是标准的master/slave模式,用户与master交互,master将job分布到slave上运行. jenkins的基本概念: 1. master, 也就是jenkins的 ...
- eclipse手动安装alibaba代码规范插件
如果你的开发环境无法访问外网,那么手动安装阿里巴巴的代码规范插件是一个不错的选择.另外,很多教程说该插件需要jdk1.8以上,我试了一下jdk1.7也是可以运行的,更低的版本就不知道了,貌似jdk1. ...
- How to Change MAC Address on Ubuntu
1 Open Terminal. 2 Log in as root so type: sudo -i and then write your password. 3 View your cur ...
- abp项目中无法使用HttpContext.Current.Session[""]的问题
web项目Global.asax.cs中加入如下代码 public override void Init() { this.PostAuthenticateRequest += (sender, e) ...
- 【NIFI】 Apache NiFI 与 SQL 操作
本里需要基础知识:[NIFI] Apache NiFI 安装及简单的使用 查询SQL 1.拖入一个 Processor:ExecuteSQLRecord(执行sql记录) 2.配置,SETTINGS的 ...
- codeforces C. Functions again
题意:给定了一个公式,让你找到一对(l,r),求解出公式给定的F值. 当时没有想到,我把(-1)^(i-l)看成(-1)^i,然后思路就完全错了.其实这道题是个简单的dp+最长连续子序列. O(n)求 ...
- Bayes’s formula for Conditional Probability
Conditional Probability Example:In a batch, there are 80% C programmers, and 40% are Java and C prog ...