一、什么是字典树
字典树(Trie树、前缀树)是一种用于快速检索的多叉树结构。字典树把字符串看成字符序列,根据字符串中字符序列的先后顺序构造从上到下的树结构,树结构中的每一条边都对应着一个字符。字典树上存储的字符串被视为从根节点到某个节点之间的一条路径,并在终点节点上做个标记"该节点对应词语的结尾",正因为有终点节点的存在,字典树不仅可以实现简单的存储字符串,还可以实现字符串的映射,只需要将相对应的值悬挂在终点节点上即可。
二、字典树的C语言实现
首先是我自己的实现
typedef struct {
struct Trie* children[26];
bool isEnd;
} Trie;
Trie* trieCreate() {
Trie* res = (Trie *)malloc(sizeof(Trie));
res->isEnd = false;
for (int i=0;i<26;++i) {
res->children[i] = NULL;
}
return res;
}
void trieInsert(Trie* obj, char * word) {
while (*word != '\0') {
if (obj->children[*word-'a'] != NULL) {
obj = obj->children[*word-'a'];
} else {
obj->children[*word-'a'] = trieCreate();
obj = obj->children[*word-'a'];
}
++word;
}
obj->isEnd = true;
}
bool trieSearch(Trie* obj, char * word) {
while (*word != '\0') {
if (obj->children[*word-'a'] != NULL) {
obj = obj->children[*word-'a'];
} else {
return false;
}
++word;
}
return obj->isEnd;
}
bool trieStartsWith(Trie* obj, char * prefix) {
while (*prefix != '\0') {
if (obj->children[*prefix-'a'] != NULL) {
obj = obj->children[*prefix-'a'];
} else {
return false;
}
++prefix;
}
return true;
}
void trieFree(Trie* obj) {
for (int i=0;i<26;i++) {
if (obj->children[i] != NULL) {
trieFree(obj->children[i]);
}
}
free(obj);
}
官方的代码比我的要好一些,但是好的有限,就是初始化的时候用了memset,比for循环要好
memset(ret->children, 0, sizeof(ret->children));
但是这些代码的时间都比较长,我第一次测试提交的代码时间很短,我后来发现是因为我释放内存了,所以时间变长了,不释放内存的话就很快。
三、字典树的C++实现
class Trie {
private:
vector<Trie*> children;
bool isEnd;
Trie* searchPrefix(string prefix) {
Trie* node = this;
for (char ch : prefix) {
ch -= 'a';
if (node->children[ch] == nullptr) {
return nullptr;
}
node = node->children[ch];
}
return node;
}
public:
Trie() : children(26), isEnd(false) {}
void insert(string word) {
Trie* node = this;
for (char ch : word) {
ch -= 'a';
if (node->children[ch] == nullptr) {
node->children[ch] = new Trie();
}
node = node->children[ch];
}
node->isEnd = true;
}
bool search(string word) {
Trie* node = this->searchPrefix(word);
return node != nullptr && node->isEnd;
}
bool startsWith(string prefix) {
return this->searchPrefix(prefix) != nullptr;
}
};