前缀树( 又名:TRIE树、单词查找树、字典树) 和 后缀树(Suffix树)

概念

前缀树:将海量字符串存储在一棵树中。
后缀树:将一个字符串分解成一棵树。

前缀树

《前缀树( 又名:TRIE树、单词查找树、字典树) 和 后缀树(Suffix树)》

 

《前缀树( 又名:TRIE树、单词查找树、字典树) 和 后缀树(Suffix树)》

 

节点的结构体:

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代表从第一个字符为起点,终点不用说都是字符串的末尾。 

《前缀树( 又名:TRIE树、单词查找树、字典树) 和 后缀树(Suffix树)》

 
以上面的后缀,我们建立一颗后缀树。如下图,为了方便看到后缀,我没有合并相同的前缀。 

《前缀树( 又名:TRIE树、单词查找树、字典树) 和 后缀树(Suffix树)》

 
后缀树是把一个字符串所有后缀压缩并保存的字典树,所以我们把字符串的所有后缀还是按照字典树的规则建立,就成了上图的样子。 
注意还是和字典树一样,根节点必须为空。

下面说下更加节省空间的方案。 既然存储的都是后缀,那么只需要保存该后缀是从源字符串的第几个字符开始的就可以了,没必要全部存储。

《前缀树( 又名:TRIE树、单词查找树、字典树) 和 后缀树(Suffix树)》

 
因为有些后缀串可能是单串,并不和其他的共用同一个前缀。 
比如上图中的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

 

    原文作者:Trie树
    原文地址: https://blog.csdn.net/sinat_38972110/article/details/82499367
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞