Trie树(又称字典树、单词查找树)是一种树型的数据结构,常用于保存和查找字符串,是一种十分高效率的存储和检索方式。
Trie树原理
我们先假设有六个字符串需要存储:abc、abcd、abef、cfgh、bc、bcd。Trie树的存储原理是在存储时首先创建一个根节点,用于以后统一检索,然后再由这个根节点开始逐项创建子节点用以存储字符串中的每个元素,下面是存储字符串abc的过程:首先创建了根节点,然后创建节点存储字符a,再创建节点存储字符b,再创建节点存储字符c,最后会做一个标记表示从a-->c的节点集是一个字符串。
以此类推,我们可以逐项画出剩下五个字符串存储完后的Trie树结构,如果一些节点已有(两字符串前面部分相同)后续就不用再反复创建了。
Trie树存储
那么我们下面用代码来实现一下Trie树的存储,这里我们假定存储的字符串是只包含小写字母的字符串。首先照旧引入头文件,然后创建三个关键的变量:Node数组、cont数组和index变量。Node数组相当于Trie树里面的节点,它用来存储字符串里面的字母。cont数组用来记录以某个节点为结束的字符串的个数。而index则表示给每一个新的节点一个独一无二的标记,也是当前存储的下标,利用这个index可以定位到一个节点。这里N表示我们最多可以存储长度为N的字符串,也可以表示树最高的高度,M表示每一个节点最多可以向下扩展的枝的个数(这里设置为26的原因是最多就26个字母)。
#include<iostream>
using namespace std;
const int N = 100,M = 26;
int Node[N][M], cont[N], index;
之后我们就可以着手写存储的函数了,我们计划写一个Insert函数来存储,这里再定义一个p变量,它表示当前存储到哪个字母(注意第0个为根节点,不存储东西)。然后再写一个for循环,当这个字符串存储到最后一个字母(即str[i]为'\0'时就结束)后就结束。我们存储一个字母的方式是将其转换为对应的数字存储,这里我们可以直接通过字母减去字符‘a’得到它们对应的数字,例如a就是0,b就是1。之后我们需要做一个判断,判断当前字母的节点是否之前已经被创建(例如之前就有abc,那么我们存储abcd的话就只需要在abc字符串的基础上只存储一个d元素就行)。判断的方式也很简单,就判断那个节点有没有被标记(也就是有没有它的的index)。有的话直接跳过到下一个节点,没有的话就创建一个(先让index加加再赋值)。最后我们寻找该字符串的下一个字母即可,具体的操作是将p变量指向下一个位置p=Node[p][u](继续重复判断该位置有没有被创建节点等操作)。最后我们让记录字符串个数的cont数组的对应标志位加加即可。
void Insert(char str[])
{
int p = 0;
for (int i = 0; str[i]!='\0'; i++)
{
int u = str[i] - 'a';
if (Node[p][u] == 0)
Node[p][u] = ++index;
p=Node[p][u];
}
cont[p]++;
}
Trie树搜索
搜索我们使用Query函数来实现,它的实现逻辑和Insert函数类似,都是在树中搜索,一旦我们需要搜索的那个字符串里一个字符没有在Trie树中搜到,那么我们就直接return0返回,以此判定没有该字符,有的话我们就返回在树中该字符串的个数。
int Query(char str[])
{
int p = 0;
for (int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
if (Node[p][u] == 0)
return 0;
p = Node[p][u];
}
return cont[p];
}
总体代码及例子
我们将上面的实验实现一下,首先准备好几个字符串:abc、abcd、abef、cfgh、bc、bcd。然后再将其插入到Trie树中,这里我直接放入字符串,所以后面我将形参换为一个常变量:
Insert("abc");
Insert("abcd");
Insert("abef");
Insert("cfgh");
Insert("bc");
Insert("bcd");
然后再将bc的数目读出来:
cout << query("bc");
总体代码如下:
#include<iostream>
using namespace std;
const int N = 100,M = 26;
int Node[N][M], cont[N], index;
void Insert(const char str[])
{
int p = 0;
for (int i = 0; str[i]!='\0'; i++)
{
int u = str[i] - 'a';
if (Node[p][u] == 0)
Node[p][u] = ++index;
p=Node[p][u];
}
cont[p]++;
}
int query(const char str[])
{
int p = 0;
for (int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
if (Node[p][u] == 0)
return 0;
p = Node[p][u];
}
return cont[p];
}
int main()
{
Insert("abc");
Insert("abcd");
Insert("abef");
Insert("cfgh");
Insert("bc");
Insert("bcd");
cout << query("bc");
return 0;
}