一、什么是Trie树(前缀树)
前缀树是N叉树的一种特殊形式。通常来说,一个前缀树是用来存储字符串的。前缀树的每一个节点代表一个字符串(前缀)。每一个节点会有多个子节点,通往不同子节点的路径上有着不同的字符。子节点代表的字符串是由节点本身的原始字符串,以及通往该子节点路径上所有的字符组成的。前缀树有着广泛的应用,例如自动补全,拼写检查等等
下面是前缀树的一个例子:
二、实现方式
(1)用数组实现
如果我们只存储含有字母 a 到 z 的字符串,我们可以在每个节点中声明一个大小为26的数组来存储其子节点。对于特定字符 c,我们可以使用 c - 'a' 作为索引来查找数组中相应的子节点。
该方法访问子节点十分快捷。访问一个特定的子节点比较容易,因为在大多数情况下,我们很容易将一个字符转换为索引。但并非所有的子节点都需要这样的操作,所以这可能会导致空间的浪费。
struct TNode
{
char ch;
vector<TNode*> children;
bool isWord;
string str;
TNode(char c)
{
ch = c;
isWord = false;
children.resize(26, NULL);
}
};
class Trie {
private:
TNode* root;
public:
/** Initialize your data structure here. */
Trie() {
root = new TNode('/');
}
/** Inserts a word into the trie. */
void insert(string word) {
TNode* p = root;
for(int i = 0; i < word.size(); ++i)
{
int index = word[i]-'a';
if(p->children[index] == NULL) //子节点中没有当前字符
{
p->children[index] = new TNode(word[i]);
}
p = p->children[index];
}
p->isWord = true;
p->str = word;
}
/** Returns if the word is in the trie. */
bool search(string word) {
TNode* p = root;
for(int i = 0; i < word.size(); ++i)
{
int index = word[i] - 'a';
if(p->children[index] == NULL)
return false;
p = p->children[index];
}
return p->isWord;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
TNode* p = root;
for(int i = 0; i < prefix.size(); ++i)
{
int index = prefix[i] - 'a';
if(p->children[index] == NULL)
return false;
p = p->children[index];
}
return true;
}
};
(2)用HashMap实现
使用 Hashmap 来存储子节点。我们可以在每个节点中声明一个Hashmap。Hashmap的键是字符,值是相对应的子节点。
该方法通过相应的字符来访问特定的子节点更为容易。但它可能比使用数组稍慢一些。但是,由于我们只存储我们需要的子节点,因此节省了空间。这个方法也更加灵活,因为我们不受到固定长度和固定范围的限制。
struct Node
{
bool isword;
int pos;
string str;
unordered_map<char, Node*> mp;
Node()
{
isword = false;
}
};
class Trie
{
private:
Node* root;
public:
Trie()
{
root = new Node();
}
void insert(string word)
{
Node* p = root;
for(int i = 0; i < word.size(); ++i)
{
if(p->mp.find(word[i]) == p->mp.end())
p->mp[word[i]] = new Node();
p = p->mp[word[i]];
}
p->isword = true;
p->str = word;
}
int search(string word)
{
Node* p = root;
for(int i = 0; i < word.size(); ++i)
{
if(p->mp.find(word[i]) == p->mp.end())
return false;
p = p->mp[word[i]];
}
return p->isword;
}
};