Trie 字典树的引入
Trie,就是我们常说的字典树,一般用树形结构来建立,用图像表示可以十分清晰直观的看出整个的结构。
具体的树形结构如何建立、构造就不细说了,已经有很详细的大佬写的博客数据结构与算法(十一)Trie字典树.
这里主要说一说如何用数组的方式构建字典树。我也是今天看到一个相关的题目才接触到这个概念。因为用树形结构构建比较复杂(代码比较多),当解决一些简单的前缀或者查找问题时,就可以用数组来模拟一个简单的字典树结构。
思路
要记住是用数组来实现字典树的模拟,对于字典树中,一个字母有两种特性,分别是他所在的层数和他所在的字符串。在模拟过程中,我们也需要有这样的结构来确保一个字符在数组中的结构不会被打乱。
构建字典树的关键是一个二维数组Trie[n][26],和一个索引index。
Trie用于存放当前字典树,index表示当前字典树的最大层数。
下面直接上代码,只给出插入函数的部分,实际的应用当然是多种多样的。
//n的值自己定义,其实用动态数组的话是最好的
#define n 2000;
int Trie[n][26],index=1;
void insert(string s) {
int u = 0;
int n = s.size();
for(int i = 0; i < n; i++) {
int c = s[i]-'a';
if(!Trie[u][c]) {
memset(Trie[index], 0, sizeof(Trie[index]));
Trie[u][c] = index++;
}
u = Trie[u][c];
}
}
乍一看代码其实还是有点难理解,我还是想了一会。可以把这个结构想象成是把树的每一层分开插入到数组里,其中第一层是公用的,后面的每一层都只属于上面的某一个格子,是这个格子在树形结构中的子节点,格子的整形数字表示的是他的子节点的行数。
模拟这个结构,假设按照顺序插入sae、pain、pand,dog,我做了一个exel表格,可以对比上面的树形结构来看。
这样看起来就比较舒服了,也可以很容易的找到单词的对应关系。
应用
上面的代码只给出了建里数组的过程,如果想要实际的实现一些功能,可以通过添加变量的方式来实现。
查找
不需要额外添加变量,只需要检查每次查找所在的位置Trie[x][y]是否不为0即可。
最小唯一前缀
给定一组个字符串,为每个字符串找出能够唯一识别该字符串的最小前缀。
可以添加一个数组val[n],用来表示在该处之前有公共前缀的数目,相当于在字典树节点上添加了一个变量x来表示有几个单词用到了这个结点。
下面给出新的构造函数和查找的函数:
#define n 2000;
int Trie[n][26],index=1;
int val[n];
void insert(string s) {
int u = 0;
int n = s.size();
for(int i = 0; i < n; i++) {
int c = s[i]-'a';
if(!Trie[u][c]) {
memset(Trie[index], 0, sizeof(Trie[index]));
val[index]=0;
Trie[u][c] = index++;
}
u = Trie[u][c];
val[u]++;
}
}
void query(string s) {
int u = 0;
int n = s.size();
for(int i = 0; i < n; i++) {
putchar(s[i]);
int c = Trie(s[i]);
if(val[Trie[u][c]] == 1) return ;
u = Trie[u][c];
}
}
查询字符串出现的次数
思路同上