Trie
Trie,又称字典树或前缀树。是一棵有根的多叉树。用于高效存储和查找字符串集合。
字典树从根到树上某一结点的路径就是一个字符串。
一棵字典树的构造过程图解:
字典树的度和字符集有关,英文字符集是26个字母,那么字典树的度就小于等于26。
字典树的每一个结点都要有一个标记,以表示该结点是否是一个字符串的终点。如上图,如果我们要查找 abc ,当查找到 c 结点的时候,由于 c 结点标记不是字符串的终点,那么就可以判断字典树内没有这个字符串。
标记可以是 bool isEnd
以表示这个结点是否是一个字符串的终点,也可以是 int cnt
以统计以该结点为终点的字符串的个数。
C++类封装的版本:
vector<Trie*> child
存储一个结点的26个孩子结点的指针。cnt
表示以当前结点为终点的字符串的个数。
class Trie
{
private:
vector<Trie*> child;
int cnt;
public:
Trie() :child(26), cnt(0) {}
void insert(const string& s)
{
Trie* p = this;
for (char c : s)
{
c -= 'a';
if (p->child[c] == nullptr)
p->child[c] = new Trie;
p = p->child[c];
}
++p->cnt;
}
int find(const string& s) const
{
const Trie* p = this;
for (char c : s)
{
c -= 'a';
if (p->child[c] == nullptr)
return 0;
p = p->child[c];
}
return p->cnt;
}
};
C语言无封装,使用二维数组模拟的版本:
child[i][j]
表示编号为i
的结点的j
孩子的编号。i
为0
表示根结点,根结点为空结点,j
映射一个字符。cnt[i]
表示以第i
个结点为终点的字符串的个数。idx
用来给结点编号。
const int N = 100010;
int child[N][26], cnt[N], idx;
void insert(char* str)
{
int p = 0;
for (int i = 0; str[i]; ++i)
{
int c = str[i] - 'a';
if (!child[p][c]) child[p][c] = ++idx;
p = child[p][c];
}
++cnt[p];
}
int find(char* str)
{
int p = 0;
for (int i = 0; str[i]; ++i)
{
int c = str[i] - 'a';
if (!child[p][c]) return 0;
p = child[p][c];
}
return cnt[p];
}