字典树
字典树(Trie)是一种空间换时间的数据结构,是一棵关于“字典”的树。主要用于统计、排序和保存大量的字符串。
字典树是通过利用字符串的公共前缀来节约存储空间,因此字典树又叫前缀树。字典树是对于字典的一种存储方式。这个词典中的每个“单词”就是从根节点出发一直到某一个目标节点的路径,路径中每条边的字母连起来就是一个单词。
假如我们要存储(cook code compare hope help com)
它的tired树为:
星星表示标记,当储存结束一个字符串后,尾节点会产生一个标记,表示当前字符串已经结束了。
删除操作
情况一:在这条链上只有一个单词,则从root开始到标记点全部删除
情况二:该单词是别的单词的前缀(com是compare的前缀),去掉标记即可
情况三:该单词是一个分支(cook和code是两个分支),从分支点到标记点全部删除
代码部分
空间实现方法:
用数组模拟空间的方式
定义变量:
idx:代表字典树中用到了的结点的下标,idx的大小只与插入字典树的先后顺序有关
trie[节点个数N][26]:N表示节点数,26表示总的子节点数。
0号点既是根节点,又是空节点
cnt[] :存储以每个节点结尾的单词数量
代码:
int trie[N][26], cnt[N], idx;
//idx 当前用到了的结点的下标
// 0号点既是根节点,又是空节点
// trie[][]存储树中每个节点的子节点
// cnt[]存储以每个节点结尾的单词数量
// 插入一个字符串
void insert(char *str)
{
int p = 0; //从根节点出发插入
for (int i = 0; str[i]; i ++ )
{
int u = str[i] - 'a'; // u代表 a ~ 字母 p代表下标
if (!trie[p][u])
trie[p][u] = ++ idx; //如果 p 结点不存在 u 这个儿子的话,就创建出来
p = trie[p][u]; //trie[]数组里存的是下标 是下一个结点的下标
}
cnt[p] ++ ; //从 root 下来第 p个结点处存在的单词数+1
}
// 查询字符串出现的次数
int query(char *str)
{
int p = 0; //从根节点出发查询
for (int i = 0; str[i]; i ++ )
{
int u = str[i] - 'a';
if (!trie[p][u]) return 0; //不存在这个单词的话下面肯定也没有单词了 结束
p = trie[p][u]; //插入时就已经设置了 trie[]的值 (是下一个结点的下标)
}
return cnt[p];//找到这个单词,输出这个单词在集合中出现的次数
}
01-trie
我们的字符集只有01两种元素的时候,我们可以构造一颗二叉树,0的分支在左边,1的分支在右边,这就是01trie树。
它可以处理这样的一个经典问题:
给你若干个数,选出其中两个数使得它们的异或结果最大/最小
题目:
思路:
代码:
# include <stdio.h>
# include <string.h>
const int n = 100010;
int a[n];
int g[n * 31][2]; //每个数字由32位的二进制组成,所以深度为31(第一位是符号位,所以只有31的深度)
int idx = 1; //编号
int max(int a, int b)
{
if ( a > b)
return a;
else
return b;
}
void insert(int x) //在01trie树上插入数字
{
int p = 0;
int t;
for (int i = 30; i>=0; --i)
{
t = x >> i & 1;
if (g[p][t] == 0)
{
g[p][t] = idx;
idx = idx + 1;
}
p = g[p][t];
}
}
int query(int x) //对每个数字都求出异或的最大值
{
int p = 0;
int t;
int res = 0;
for (int i=30; i>=0; --i)
{
t = x >> i & 1;
if (g[p][1-t] != 0) //只有第i位的数字与下方连接的数字不一样,并且存在该数字,才是最大值
{
res = res + 1 << i;
p = g[p][1-t]; 进入该节点
}
else
p = g[p][t];进入该节点
}
return res;
}
int main()
{
memset(g, 0, sizeof(g));
int N;
int ans;
scanf("%d", &N);
for (int i=0; i<N; ++i)
{
scanf("%d", &a[i]);
insert(a[i]);
}
for (int i=0; i<N; ++i)
ans = max(ans, query(a[i]));
printf("%d", ans);
}