后缀树(一)定义及构造

后缀树(Suffix tree):

:一个具有m个词的字符串S的后缀树T,就是一个包含一个根节点的有向树,该树恰好带有m个叶子,这些叶子被赋予从1到m的标号。 每一个内部节点,除了根节点以外,都至少有两个子节点,而且每条边都用$的一个非空子串来标识。出自同一节点的任意两条边的标识不会以相同的词开始。后缀树的关键特征是:对于任何叶子i,从根节点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀,即S[i,…,m]。树中节点的标识被定义为从根到该节点的所有边的标识的串联。

后缀:一个长度为m的字符串序列S=s1 s2 ....sm,记Si=si si+1 .....sm为S的第 i 个后缀,显然S1=S 为原来的字符串;

后缀树的定义:长度为m的序列S,其后缀树是一个有向树,满足以下条件:

1)有m个叶结点; 2)除了根结点和叶结点,每一个内部结点至少有两条边(子节点),每条边对应S中的一个非空序列;

3)从任何一个内部结点出发的两条边对应的字符串序列的第一个字符都不相同;

4)从根结点到叶结点的路径上的字符序列构成了S从i开始的一个后缀字符串;

路径标签:一个路径上对应的字符序列称为路径标签;

结点标签:从根结点开始到此结点对应的路径的标签称为结点标签;

并不是所有的字符序列都有后缀树,例如xabxa(其后缀有xabxa,abxa,bxa,xa,a)xa为xabxa的前缀,为了解决此问题,通常在字符串末尾加上$符号,使得任何一个后缀都不为其他后缀的前缀。

(xabxa$的后缀树)

 注:从根结点到叶子结点路径上的字符(词)表示对应叶节点 i 开始的某一个后缀字符串,叶子结点存储了起始位置 i 有几个字符(词)就有几个叶子结点,根结点和内部结点不存储任何数据,只有叶子结点和边存储数据;

隐含后缀树:序列S的隐含后缀树是指,序列S$的后缀树,去掉那些有$的边的$符号,之后将空边删除所得到的树;

(xabxa$的隐含后缀树)

即:隐含后缀树构造即删除所有边的$符号之后将空边删除;

后缀树的构造:

根据S字符串的前缀s1 s2....si构造隐含后缀树Ti,当i=m时即可构造出S的隐含后缀树;

后缀树伪代码
1、初始化一个隐含后缀树
for i 从 1 到 m:  //m为字符串长度
   逐步构造隐含后缀树
   for j 从 1 到 i+1:
        #后缀拓展规则
        在已经构建好的后缀树中找到从root结点出发
        标记位S[j....i]的序列,如果需要的话将
        S[i+1]加入到这条路径后面
   进行下一次隐含后缀树的构造
end  //完成整个后缀树的构造

后缀的扩展规则:

令β=S【j....i】,这里的β为S【1....i】的某一个后缀,第j步扩展是为了保证序列β,S【i+1】在树中;

1、规则1:路径β是以一个叶子结点结尾的只需将S【i+1】直接加入在叶子结点上面;

(路径β以一个叶子结点为结束,直接在此路径上增加一个S【i+1】)

2、规则2:路径β后面没有以S【i+1】开始,但至少有一个路径是β的延续,如果β终止于内部结点则新建一个叶子结点

作为这个内结点的子结点并将此边标记为S【i+1】,当β是在一条边的中间时除了建立一个子结点外还要建立一个从根结点

出发标记为β的内部结点。

(路径β在中间部分则从其末尾插入一个内部结点以及生成这个内部结点的子结点其路径标记为S【i+1】)

3、规则3:有某个路径是β的末端开始且S【i+1】开头则无需进行任何操作;

(有以β开头的路径什么也不做)

例子:字符串S=“axabxb“的后缀树的逐步构建;

字符 a x a b x b
下标 1 2 3 4 5 6

 时间复杂度分析:

对于内层循环每一次都要寻找一条路径β,其时间复杂度为O(β)内外层循环为O(i^2),合起来时间复杂度为O(m^3);

发布了79 篇原创文章 · 获赞 81 · 访问量 5735

猜你喜欢

转载自blog.csdn.net/weixin_44638960/article/details/102743453