Algorithm 为什么后缀树中需要哨兵字符?

Algorithm 为什么后缀树中需要哨兵字符?,algorithm,suffix-tree,Algorithm,Suffix Tree,为什么我们在实现时需要将“$”附加到原始字符串中?我怀疑它是为了进行遍历。当您从后缀树生成某些内容时,您需要知道是否处于字符串结束的节点,如果不是,那么您知道必须继续。查看后缀树提供线性时间解决方案的节点,您需要$哨兵来确定您已到达字符串终止的节点。你不能在A-NA之后完成 来自维基百科 在使用特定构造算法时,在字符串末尾追加一个(甚至多个)特殊字符可能有特殊的原因,无论是在后缀树还是后缀数组的情况下 但是,后缀树的最根本原因是后缀树的两个属性的组合: 后缀树是PATRICIA树,也就是说,与t

为什么我们在实现时需要将“$”附加到原始字符串中?

我怀疑它是为了进行遍历。当您从后缀树生成某些内容时,您需要知道是否处于字符串结束的节点,如果不是,那么您知道必须继续。查看后缀树提供线性时间解决方案的节点,您需要
$
哨兵来确定您已到达字符串终止的节点。你不能在
A-NA
之后完成

来自维基百科


在使用特定构造算法时,在字符串末尾追加一个(甚至多个)特殊字符可能有特殊的原因,无论是在后缀树还是后缀数组的情况下

但是,后缀树的最根本原因是后缀树的两个属性的组合:

  • 后缀树是PATRICIA树,也就是说,与tries的边缘标签不同,边缘标签是由一个或多个字符组成的字符串
  • 内部节点仅存在于分支点
  • 这意味着您可能会遇到这样的情况,即一个边标签是另一个边标签的前缀:

    这里的想法是,右边的黑色节点是一个叶节点,即后缀在这里结束。但如果文本有后缀
    aa
    ,则单个字符
    a
    也必须是后缀。但是我们无法存储后缀在第一个
    a
    之后结束的信息,因为
    aa
    形成了树的一条连续边(上面的属性1)。我们必须引入一个中间节点来存储信息,如下所示:

    但这是非法的,因为属性2:除非有分支点,否则内部节点必须不存在

    如果我们能够保证文本的最后一个字符是整个字符串中其他地方都不出现的字符,那么问题就解决了。美元符号通常被用作这方面的符号

    显然,如果最后一个字符不在其他地方出现,则字符串末尾不可能有任何重复(例如
    aa
    ,或者更复杂的重复,例如
    abcabc
    ),因此不会出现非分支内部节点的问题。在上面的示例中,将
    $
    放在字符串末尾的效果是:

    现在有三个后缀:
    aa$
    a$
    $
    ,但没有一个是另一个后缀的前缀。显然,这意味着我们需要引入一个内部节点,现在总共有三个叶子。因此,可以肯定的是,这样做的好处是而不是节省空间或使任何事情变得更有效。这只是保证上述两个属性的一种方法。当我们证明后缀树的某些有用特性时,这些属性很重要,包括其内部节点数在字符串长度上是线性的(如果允许非分支内部节点,则不能)

    这也意味着,在实践中,可以使用不同的方法处理作为其他后缀前缀的后缀,以及非分支内部节点。例如,如果您使用众所周知的Ukkonen算法来构造树,则无需在末尾附加唯一字符即可完成此操作;您只需确保在最后一次迭代之后,将非分支内部节点放在每个隐式后缀的结尾(即在边缘中间结束的每个后缀)。 同样,在构建后缀树或数组之前,将
    $
    放在文本末尾可能还有更进一步、更具体的原因。例如,在基于DC(差异覆盖)原则的后缀数组构造算法中,必须在字符串末尾放置两个
    $
    符号,以确保即使是字符串的最后一个字符也是完整字符三角图的一部分,因为该算法基于三角图排序。此外,在某些特定情况下,必须以特殊方式解释唯一的
    $
    字符。对于Ukkonen构造算法,
    $
    是唯一的就足够了;对于DC后缀数组算法,除了唯一性外,
    $
    必须在字典上比所有其他字符小,并且在基于后缀树的循环字符串切割算法(最近提到)中,实际上有必要将
    $
    解释为字典上最大的字符