文章目录
Trie树是一种高效存储、查询字符串的数据结构
映射规则
1. 小写字母的下标映射
int ValueHash(ValueType v) {
return v - 'a';
}
2. 大写映射
int ValueHash(ValueType v) {
return v - 'A';
}
3. 大小写混合映射
int ValueHash(ValueType v) {
if(v >= 'a' && v <= 'z')
return v - 'a';
return v - 'A' + 26;
}
4. 整数映射
int ValueHash(ValueType v) {
return v - '0';
}
存储字符串
#include<iostream>
const int N = 1e6 + 10;
using namespace std;
int son[N][26],book[N],cur;(1)
int n ;
char str[N],ch;
void insert(char str[])
{
int p = 0;(2)
for(int i = 0 ; str[i] ;i ++)//遍历整个数组
{
int u = str[i] - 'a';(3)
if(!son[p][u]) son[p][u] = ++ cur; // 同时idx自增 使得每个字符的映射拥有唯一的下标
p = son[p][u];
}
book[p] ++ ;
}
int query(char *str)
{
int p = 0;
for (int i = 0; str[i]; i ++ )
{
int u = str[i] - 'a';
if (!son[p][u]) return 0;
p = son[p][u];
}
return book[p];
}
int main()
{
int n;
cin>>n;
while (n -- )
{
char op;
cin >> op >> str;
if (op == 'I') insert(str);
else printf("%d\n", query(str));
}
return 0;
}
Ps:
(1)son[p][u]
表示 p 这个节点是否含有u这个映射
(2)根节点 最初对应的映射是 0
(3)将小写字母a ~ z
映射到0 ~ 25
方便利用数组操作
(4)
存储二进制串
将一个整数看成一个31位的二进制数串 从高位开始 依次 选择与当前位 不同的 分支 当走到叶节点的时候 就是最大异或对
//
#include<iostream>
#include<cstdio>
#include<vector>
const int N = 100050;
int n;
using namespace std;
int a[N];
int son[N * 31][2],idx;//idx是全局变量
void insert(int x)
{
int p = 0;
for(int i = 30 ;i >= 0 ; i --)
{
bool u = (x >> i) & 1 ;//取出每一位的值
if(!son[p][u]) son[p][u] = ++ idx;//如果没有这个节点 就创建一个节点
p = son[p][u];
}
}
int query(int x)//在已有的Trie树中 寻找能匹配到的数 并且返回 x ^ 最匹配的数的
{
int p = 0;
int ret = 0;
for(int i = 30 ;i >= 0 ; i --)
{
bool u = (x >> i) & 1 ;
if(son[p][!u])
{
p = son[p][!u];
ret = (ret<<1) + !u;
}
else
{
p = son[p][u];
ret = (ret<<1) + u;
}
}
return ret ^ x;
}
int main()
{
cin >> n;
for(int i = 0; i < n ; i ++) scanf("%d",&a[i]);
for(int i = 0; i < n ; i ++) insert(a[i]);
int ret = 0;
for(int i = 0; i < n ; i ++) ret = max(ret, query(a[i])); //寻找对应的异或值
cout << ret << endl;
return 0;
}
字典树的 应用 与 扩展
1、查询前缀
题干
给定
n
个长度不超过20
的小写字母组成的字符串。再给出m
次询问,每次询问一个字符串s
,求出以s
为前缀的字符串有多少个。
思路
直接需要遍历字符串 ,获取结尾结点的 num值即可