📅  最后修改于: 2023-12-03 15:35:27.376000             🧑  作者: Mango
Ukkonen算法是一种用于构建后缀树的算法,它的时间复杂度是线性的,即 O(n)。它将每一个后缀插入后缀树中,在插入过程中,它会利用一些特殊技巧来避免显式地构造出字符串的所有后缀。这种技巧可以使得算法的时间复杂度来到线性。
在本篇文章中,我们将介绍Ukkonen算法的前半部分,也就是如何在O(n^2)的时间内构造每一个后缀的后缀树。
Ukkonen算法构造字符串S的后缀树的过程如下所示:
我们将用Python语言实现Ukkonen算法,实现代码如下:
class Node:
def __init__(self, label="", id=0):
self.label = label
self.id = id
self.children = {}
class SuffixTree:
def __init__(self, string):
self.string = string
self.root = Node()
self.active_node = self.root
self.active_edge = ""
self.active_length = 0
self.leaf_end = -1
self.remaining_suffix_count = 0
self.split_end = 0
self.last_parent_node = None
def edge_length(self, node):
if node == self.root:
return 0
return len(node.label)
def walk_down(self, current_node):
if self.active_length >= self.edge_length(current_node):
self.active_edge = self.string[self.active_edge_index + self.edge_length(current_node)]
self.active_length -= self.edge_length(current_node)
self.active_node = current_node
return True
return False
def extend_suffix_tree(self, pos):
self.leaf_end = pos
self.remaining_suffix_count += 1
self.last_parent_node = None
while self.remaining_suffix_count > 0:
if self.active_length == 0:
self.active_edge_index = pos
if self.active_edge not in self.active_node.children:
leaf_node = Node(label=self.string[pos:], id=len(self.active_node.children))
self.active_node.children[self.active_edge] = leaf_node
if self.last_parent_node is not None:
self.last_parent_node.suffix_link = self.active_node
self.last_parent_node = None
else:
next_node = self.active_node.children[self.active_edge]
if self.walk_down(next_node):
continue
if self.string[next_node.label[self.active_length]] == self.string[pos]:
self.active_length += 1
if self.last_parent_node is not None and self.active_node != self.root:
self.last_parent_node.suffix_link = self.active_node
self.last_parent_node = None
break
self.split_end = self.active_edge_index + self.active_length - 1
split_node = Node(label=next_node.label[:self.active_length], id=len(self.active_node.children))
self.active_node.children[self.active_edge] = split_node
leaf_node = Node(label=self.string[pos:], id=len(split_node.children))
split_node.children[self.string[self.split_end]] = next_node
split_node.children[self.string[pos]] = leaf_node
if self.last_parent_node is not None:
self.last_parent_node.suffix_link = split_node
self.last_parent_node = split_node
self.remaining_suffix_count -= 1
if self.active_node == self.root and self.active_length > 0:
self.active_length -= 1
self.active_edge_index = pos - self.remaining_suffix_count + 1
else:
self.active_node = self.active_node.suffix_link if self.active_node.suffix_link is not None else self.root
以上就是基于Ukkonen算法构造后缀树的第1部分。通过以上代码实现,我们可以看到在O(n^2)的时间内构造一个字符串的后缀树。在下一篇文章中,我们将会介绍Ukkonen算法的第2部分。