后缀树和后缀数组(后缀树的变体)在字符串处理中意义重大,在求类似最长回文字串,最长公共前缀,最长重复字串等应用中都非常频繁,属于必须掌握一组数据结构。
一,在了解后缀树之前,需要简单了解一下trie树(字典树)。
trie主要用在求词频,消除重复字符串,以及多模式匹配的AC自动机等应用中,一般跟BFS组合使用。
1,假设需要处理的字符串只有小写字母,那么一共有26个字母,亦即trie是一个类似26叉树。即其儿子数目跟处理的字符串字符最大集有关。
2,根节点不表示任何字符,从跟节点走到叶节点即是一个保存的单词(字串),可认为每一条不为NULL的指针边为一个字符。其表示字符一般是其在其父节点的儿子数组中出发的指针index加上a的ascii。
一般来说数据结构如下,
#define ALPHABET 26
typedef strcut _trie_node_t{
struct _trie_node_t* child[ALPTHABET];
bool is_word;/int word_count //视用途而定。
}trie_node_t;
二,后缀树
后缀,顾名思义就是从任意一个字符到字串结尾的字串集。
如:对于字符串asdfghjkl:
asdfghjkl(1),
sdfghjkl(2),
dfghjkl(3),
fghjkl(4),
ghjkl(5),
hjkl(6),
jkl(7),
kl(8),
l(9),
$//空集
以上这些字串都是其后缀。
那么这些字符串必然可以组成一个trie树。
构造这样的一颗trie树需要原字符串长度n的平方级的时间。
虽然后缀trie可以在O(目标串长度)内查找,但是因为构造后缀trie的复杂度太高,
所以综合起来,效率并不高。
于是大牛们出现了,1976年CMU大神Edward McCreigh(同时也是B树的共同发明者,前面的超链接里面有他解释为什么B树被叫做B树)打破了后缀trie的平方级时间界。
通过压缩只有一个儿子的节点,大大的降低了树的节点个数,于是,后缀树粉墨登场。
据说,即使在最坏的情况下,后缀树的节点总数也不会超过文本的总长度的二倍,没研究过是怎么证明这一定理的,以后有时间一定研究一下。
1995年helsinki tech cs教授E.Ukkonen对EM的方法做了一些优化,后缀树就是我们现在看到的样子了。
三,后缀数组
后缀数组是后缀树的一个变体,顾名思义,这是一个数组,数组里面是什么呢?
数组里面存放的是使给定字串的所有的后缀有序的后缀起始索引数组,那么这个序是怎么确定的呢?