概念
前缀树:将海量字符串存储在一棵树中。
后缀树:将一个字符串分解成一棵树。
前缀树
节点的结构体:
struct trieNode {
bool isEnd;//是否可以作为字符串的终结节点
trieNode *child[26];
}
前缀树:
class Trie {
private:
trieNode *root;
public:
Trie() {
root = new trieNode;
root->isEnd = false;
memset(root->child, 0, sizeof(root->child));
//注意:这里因为child是指针数组,而非数组指针,所以才能sizeof出数组长度!
}
void insert(const char *word) {
trieNode *cur = root;
while (*word) {//依次插入每个字符,直到遇到"\0". ("\0"的ascii码是0)
if (cur->child[*word - 'a'] == nullptr) {
//若该节点不存在,则新建一个节点,让其子节点指针数组全为空,且终结标志为0.
trieNode *newNode = new trieNode();
newNode->isEnd = 0;
memset(newNode->child, NULL, sizeof(newNode->child));
//将新节点挂在当前节点的当前child域中
cur->child[*word - 'a'] = newNode;
}
cur = cur->child[*word - 'a'];
word++;//当前字符在字符串中的位置
}
cur->isEnd = true;
}
bool find(const char *word) {
trieNode *cur = root;
while (*word && cur!=nullptr) {
cur = cur->child[*word - 'a'];
word++;
}
return (cur!=nullptr && cur->isEnd);
}
};
后缀树
后缀树,就是把一串字符的所有后缀保存并且压缩的字典树。相对于字典树来说,后缀树并不是针对大量字符串的,而是针对一个或几个字符串来解决问题,比如字符串的回文子串,两个字符串的最长公共子串等等。
性质:一个字符串构造了一棵树,树中保存了该字符串所有的后缀。
比如单词banana,它的所有后缀显示到下面的。1代表从第一个字符为起点,终点不用说都是字符串的末尾。
以上面的后缀,我们建立一颗后缀树。如下图,为了方便看到后缀,我没有合并相同的前缀。
后缀树是把一个字符串所有后缀压缩并保存的字典树,所以我们把字符串的所有后缀还是按照字典树的规则建立,就成了上图的样子。
注意还是和字典树一样,根节点必须为空。
下面说下更加节省空间的方案。 既然存储的都是后缀,那么只需要保存该后缀是从源字符串的第几个字符开始的就可以了,没必要全部存储。
因为有些后缀串可能是单串,并不和其他的共用同一个前缀。
比如上图中的banana这个后缀串,直接可以用1来表示起点,终点是默认的。
上图的a节点后面有两个节点标记3和5是右边字符数组的下标,对应着a->3-7,a->5-7。因为a是共有的前缀。
https://blog.csdn.net/v_july_v/article/details/6897097
https://blog.csdn.net/u013949069/article/details/78056102