我正在使用后缀树。据我所知,我正确地运行了Ukkonen算法,从任意数量的字符串构建一个通用后缀树。我现在正在尝试实现find_longest_common_substring()
方法来做到这一点。为了实现这个目的,我理解我需要在树中的所有字符串之间找到最深的共享边(在字符方面有深度,而不是边缘),并且我已经挣扎了几天才能使遍历正确
现在我在C ++中有以下内容。我将为您提供所有代码,但是对于上下文,我将每个节点的边缘保持在名为outgoing_edges
的unordered_map中,并且每个边都有一个整数recorded_strings
的向量,其中包含标识所添加的整数字符串。边缘的child
字段是它要去的节点,l
和r
分别标识其左侧和右侧索引。最后,current_string_number
是树中当前的字符串数。
SuffixTree::Edge * SuffixTree::find_deepest_shared_edge(SuffixTree::Node * start, int current_length, int &longest) {
Edge * deepest_shared_edge = new Edge;
auto it = start->outgoing_edges.begin();
while (it != start->outgoing_edges.end()) {
if (it->second->recorded_strings.size() == current_string_number + 1) {
int edge_length = it->second->r - it->second->l + 1;
int path_length = current_length + edge_length;
find_deepest_shared_edge(it->second->child, path_length, longest);
if (path_length > longest) {
longest = path_length;
deepest_shared_edge = it->second;
}
}
it++;
}
return deepest_shared_edge;
}
当我尝试调试时,我可以说,遍历运行大部分都很好,并正确记录路径长度并设置最长。但是,由于我不太了解的原因,在最内层的条件中,deepest_shared_edge
有时似乎更新到了错误的边缘。我怀疑我可能不太明白在整个递归过程中如何更新it->second
。然而,我不太确定如何解决这个问题。
我知道this类似的问题,但这种方法似乎有很大的不同,我不太确定它在这里是如何应用的。
我主要是为了娱乐和学习,所以我不一定需要工作代码来代替上面的伪代码或者只是对我困惑的地方的任何解释也是如此。
答案 0 :(得分:1)
您对deepest_shared_edge
的处理是错误的。首先,您在函数开始时执行的分配是内存泄漏,因为您永远不会释放内存。其次,递归调用的结果被忽略,因此无论它发现的最深边缘都会丢失(尽管你更新了深度,但你不能跟踪最深的边缘)。
要解决此问题,您应该将deepest_shared_edge
作为参考参数传递(就像您对longest
所做的那样),或者您可以将其初始化为nullptr
,然后检查您的回复递归调用nullptr
并适当更新。