关于前缀树的内容最好看看视频了解逻辑结构,然后代码实现一下
前缀树是一种树形数据结构,广泛用于字符串查找,思想上类似哈希。在字符串查找上有非常好的效果,但是消耗空间较大,下面给出前缀树的c++实现
#ifndef TRIE_H_INCLUDED
#define TRIE_H_INCLUDED
#include<string>
using namespace std;
//假设字符串都是小写字母
typedef struct TrieNode
{ int pass = 0; //有几个字符串经过此结点(前缀包含这个字符的字符串数量)
int end = 0; //以此结点结束的字符串的数量,如果不允许重复插入,可以改成bool
TrieNode* next[26]{nullptr}; //26个空位,准备挂下一结点a-z ,没有时置为nullptr
}TrieNode ; //前缀树结点定义
//前缀树
class Trie {
public:
TrieNode *root = nullptr; //根节点
Trie() {
root = new TrieNode(); //构造函数初始化root
}
~Trie() {
deletememory(root); //析构释放空间
}
/* 插入字符串 */
void insert(string word) {
TrieNode *temp = root;
temp->pass++;
//根节点的pass代表树上有多少字符串以空字符串为前缀,也就是字符串总数
for(unsigned int i = 0 ;i<word.size() ;i++) //遍历字符串的每个字符
{
if(temp->next[word[i]-'a'] == nullptr) //如果先前没有字符串经过此结点
temp->next[word[i]-'a'] = new TrieNode(); //建出新结点
temp = temp->next[word[i]-'a'];
temp->pass++;
}
temp->end++; //temp指向字符串最后一个结点,end++表示多了一个字符串以此结点结尾
}
/** 查找树上是否有字符串word ,也可以返回int 代表树上找到的word数量*/
bool search(string word) {
TrieNode *temp = root;
for(char c : word) //遍历字符串每个字符,也可以使用for i~word.size写法
{
if(temp->next[c-'a'] == nullptr ) //找的过程发现没路了,false
return false;
temp = temp->next[c-'a'];
}
return temp->end;
}
/** 查找树上是否有字符串含前缀prefix */
bool startsWith(string prefix) {
TrieNode *temp = root;
for(unsigned int i = 0 ;i<prefix.size() ;i++)
{
if(temp->next[prefix[i]-'a'] == nullptr)
return false;
temp = temp->next[prefix[i]-'a'];
}
return true;
}
/* 递归释放空间*/
void deletememory( TrieNode *temp) {
for(int i = 0 ;i < 26; i++) //对一个结点,将其next数组存放的后续节点全部释放
if(temp->next[i])
deletememory(temp->next[i]);
delete temp; //释放本结点空间
}
/*从树上删除字符串*/
void remove(string word) {
if(true == search(word)) //树上有这个字符串才需要删除
{
TrieNode *temp = root;
temp->pass--;
for(unsigned int i = 0 ; i< word.size() ;i++)
{
if( --temp->next[word[i]-'a']->pass == 0) //唯一经过该结点的字符串被删除
{
deletememory(temp->next[word[i]-'a'] ); //递归释放此结点后面路径
temp->next[word[i]-'a'] = nullptr; 结点置nulptr
return ;
}
temp = temp->next[word[i] - 'a'];
}
temp->end--; //如果字符串所有字符删除后,路径没变,还需要把最后结点end-1
}
}
};
#endif // TRIE_H_INCLUDED
上面所给出的实现要求字符串都是小写字母,但如果字符种类非常多,我们需要将存储下一结点的数据结构进行修改,因为定长数组的方式可能会造成空间巨大的浪费,我们可以使用哈希map的方式存储 <字符,下一结点>