实现后缀树时,为什么需要在原始字符串后附加“ $” ?
使用后缀树和后缀数组时,使用特殊的构造算法时,可能有特殊的原因要在字符串的末尾附加一个(或更多)特殊字符。
但是,对于后缀树, 最根本的根本原因 是后缀树的两个属性的组合:
这意味着您可能会遇到一个边缘标签是另一个边缘标签的前缀的情况:
这里的想法是,右侧的黑色节点是叶节点,即后缀在此处结束。但是,如果文本具有后缀aa,则单个字符a也必须是后缀。但是我们无法存储后缀在第一个之后结束的信息a,因为它aa形成了树的一个连续边(上面的属性1)。我们将不得不引入一个中间节点,可以在其中存储信息,如下所示:
aa
a
但是由于属性2,这将是非法的:除非存在分支点,否则任何内部节点都必须不存在。
如果我们可以保证文本的最后一个字符是整个字符串中其他任何地方都没有出现的字符,那么问题就解决了。美元符号通常用作该符号。
显然,如果最后一个字符不出现在其他任何地方,则在字符串的末尾不可能有任何重复(例如aa,或者甚至是更复杂的重复,例如abcabc),因此不会发生非分支内部节点的问题。在上面的示例中,放在$字符串末尾的效果是:
abcabc
$
有三种后缀现在:aa$,a$和$,但没有是另一个的前缀。显然,这意味着我们毕竟需要引入一个内部节点,并且现在总共有三片叶子。因此,可以肯定的是,这样做的好处 不是 节省空间或提高效率。这只是保证上面两个属性的一种方法。当我们证明后缀树的某些有用特性(包括其内部节点的数目在字符串的长度上是线性的)时,这些属性很重要(如果允许使用非分支内部节点,则无法证明这一点
aa$
a$
这也意味着 在实践中 ,您可能会使用不同的方式来处理作为其他后缀的前缀的后缀以及非分支内部节点。例如,如果您使用众所周知的Ukkonen算法来构造树,则可以在不将唯一字符附加到末尾的情况下进行操作。您只需要确保在最后一次迭代之后,将非分支内部节点放在每个隐式后缀(即,每个后缀在边的中间)的末尾即可。
同样,在构造后缀树或后缀数组之前, 可能还有其他更具体的原因 要放在$文本末尾。例如,在基于DC(差异覆盖)原理的后缀数组构造算法中,您必须$在字符串的末尾添加两个符号,以确保即使字符串的最后一个字符也是完整字符三字母组合的一部分,因为该算法基于三元组排序。此外,在某些情况下,$必须以特殊方式解释唯一字符。对于Ukkonen构造算法来说,$唯一就足够了。对于DC后缀阵列算法,除了唯一性外,还必须$按字典顺序比所有其他字符更小,并且在后缀树基于圆形串切割算法,它实际上是需要解释$的字典式 最大的 特点。