C++ 如何从LCP数组和后缀数组构造后缀树
标题差不多 我使用DC3算法在O(n)时间内创建了一个后缀数组。然后我用Kasai的算法在O(n)时间内创建了一个LCP数组。现在我需要从我拥有的两个数组中创建一个后缀树。你是怎么做到的? 我看了一下期刊论文,用谷歌搜索了一下四周,但我找不到一个方法C++ 如何从LCP数组和后缀数组构造后缀树,c++,string,suffix-tree,C++,String,Suffix Tree,标题差不多 我使用DC3算法在O(n)时间内创建了一个后缀数组。然后我用Kasai的算法在O(n)时间内创建了一个LCP数组。现在我需要从我拥有的两个数组中创建一个后缀树。你是怎么做到的? 我看了一下期刊论文,用谷歌搜索了一下四周,但我找不到一个方法 我看到一个coursera视频描述了这个过程,但他们没有说明他们使用的方法,我怀疑这是一个线性时间算法。实际上非常简单。后缀数组告诉您在对后缀树进行从左到右的深度优先遍历时遇到的后缀序列。LCP数组告诉您在开始对应于下一个后缀的新边之前需要向上走多
我看到一个coursera视频描述了这个过程,但他们没有说明他们使用的方法,我怀疑这是一个线性时间算法。实际上非常简单。后缀数组告诉您在对后缀树进行从左到右的深度优先遍历时遇到的后缀序列。LCP数组告诉您在开始对应于下一个后缀的新边之前需要向上走多远。假设字符串
s
末尾有一些唯一的字符(因此每个后缀都由一个叶节点表示),算法大致如下:
let root = new node
let p = new node
make p a child of root with edge label S[0] (the least suffix)
for (int i = 1; i < s.size(); i++) {
let l = LCP[i-1] (the LCP length of S[i] and S[i-1])
let prevP = null
while ((depth of p) > l) {
// note that "depth" means total edge length from root to p, not
// total number of edges from root to p
prevP := p
p := (parent of p)
}
if ((depth of p) == l) {
let q = new node
make q a child of p, with edge label S[i][l...]
p := q
} else {
// we need to "split" the edge from p to prevP
let q = new node
let prevDepth = depth of prevP
unlink prevP from p
make q a child of p, with edge label S[i-1][(depth of p)...(l - 1)]
make prevP a child of q, with edge label S[i-1][l...(prevDepth - 1)]
let r = new node
make r a child of q, with edge label S[i][l...]
p := r
}
}
return root
let root=新节点
设p=新节点
使p成为边标签为S[0](最小后缀)的根的子级
对于(int i=1;il){
//请注意,“深度”是指从根部到p的总边缘长度,而不是
//从根到p的边总数
prevP:=p
p:=(p的父级)
}
如果((p的深度)=l){
设q=新节点
使q成为p的子对象,边标签为S[i][l..]
p:=q
}否则{
//我们需要将边缘从p“分割”到prevP
设q=新节点
设prevDepth=prevP的深度
取消prevP与p的链接
使q成为p的子元素,边标签S[i-1][(p的深度)…(l-1)]
使prevP成为q的子对象,边标签为S[i-1][l…(prevDepth-1)]
设r=新节点
使r成为q的子对象,边标签为S[i][l..]
p:=r
}
}
返回根
谢谢您的回答!这个算法有名字吗?@hussainsagar我不知道。我怀疑你说的深度是什么意思。您已经说过,深度是从根到p的边的总数,而不是边长度。边的长度和边的数量有什么不同?@hussainsagar抱歉,当我谈到边的长度时,我指的是该边所承载的子字符串标签的长度。对于字符串“abcabd”,后缀树将有一个节点,该节点通过带有标签“ab”的边链接到根。所以节点的深度是2,因为“ab”的长度是2,即使它只有1条边。