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的 ...
随机推荐
- css代码插入三种方式
1.内联式 <p style="color:red;font-size: 12px">iutt</p> 2.嵌入式 <style type=" ...
- docker 运行 elasticsearch + kibana
一.elasticsearch的安装 1.从官网上拉取 elasticsearch 的镜像 docker pull elasticsearch:5.6.11docker images 2.运行容器 m ...
- error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int 错误的解决方法
一些函数定义中,在VC6中,如果没有显示的指定返回值类型,编译器将其视为默认整型:但是vs2008/vs2010不支持默认整型,解决这个问题不能修改每个没有显示指示返回值类型的函数地方,可以用排除44 ...
- NC 5系自定义显示公式
1.继承NcInnerFunction(nc.vo.pub.formulaset.function.NcInnerFunction) 在方法中引用父类方法function,并在里面写方法 @Overr ...
- Java中的四种内部类
Java中有四种内部类: 成员内部类:定义在另一个类(外部类)的内部,而且与成员属性和方法平级,故称成员内部类.类比于外部类的非静态方法,如果用static修饰就变成了静态内部类 静态内部类:使用st ...
- ubuntu配置ftp server
ubuntu配置ftp server 1. 安装vsftpd sudo apt-get install vsftpd 安装后会自动新建一个用户ftp,密码ftp,作为匿名用户登录的默认用户 sud ...
- DHT
DHT(Distributed Hash Table,分布式哈希表)类似Tracker的根据种子特征码返回种子信息的网络.DHT全称叫分布式哈希表(Distributed Hash Table),是一 ...
- Java:斐波那契数列
斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10 ...
- java web实践
语言:java.javascript 软件:eclipse.mysql 环境配置:下载jdk:配置jdk环境变量.相关教程:https://jingyan.baidu.com/article/db55 ...
- php 超时设置笔记
php.ini default_socket_timeout=5 mysql.connect_timeout = 5 max_execution_time = 5 php-fpm pm = dynam ...