目录
一.概念
又称字典树或者单词查找树,是一种能高效快速存储和查找字符串集合的数据结构。
通常用于统计和排序大量的字符串,也可用于查找字符串。(不限于字符串)
查询,插入的平均时间复杂度亦为O(logN))
二.树的构建
int son[r][x] r结点关于x的子节点
idx 标记不同的结点,每个结点对应一个下标,保证了树结构结点之间的联系
(关于idx:AcWing 835. 如何理解单(双)链表,Trie树和堆中的idx? - AcWing)
根节点r : 不存储任何数值
三.树的创建
主要思路:从根节点r = 0出发,通过判断子节点是否存在,如果子节点不存在,则创建子节点,并为其分配一个idx下标作为该节点的标记,再从下一个子节点r = son[r][x]出发,循环以上步骤。
static void insert(String s){
char[] c = s.toCharArray();
int r = 0; //从根节点开始创建,根节点不存值
for(int i=0;i<c.length;i++){
int x = c[i] - 'a';
if(son[r][x]==0) son[r][x] = ++idx;//如果子节点不存在,为之分配一个下标作为该节点的标记
r = son[r][x];//指向子节点
}
cnt[r]++;//cnt[]记录该字符串出现的次数(根据字符串最后一个节点记录),该步骤使该字符串的次数+1
}
四.查询
思路:与创建树相似,对于不同的题有不一样的具体细节
//判断字符串出现的次数
static int query(String s){
int r = 0;//从根节点开始
char[] c = s.toCharArray();
for(int i=0;i<c.length;i++){
int x = c[i] - 'a';
if(son[r][x]==0)//如果子节点不存在,说明该字符串不存在,返回0
return 0;
r = son[r][x];//指向下一个子节点
}
return cnt[r];//返回字符串出现的次数
}
五.Tire的应用
截取自(5条消息) 海量数据处理之Tire树(字典树)_ts173383201的博客-CSDN博客
六.例题:求最大异或数
在给定的 NN 个整数 A1,A2……ANA1,A2……AN 中选出两个进行 xorxor(异或)运算,得到的结果最大是多少?
输入格式
第一行输入一个整数 NN。
第二行输入 NN 个整数 A1A1~ANAN。
输出格式
输出一个整数表示答案。
数据范围
1≤N≤10^5,
0≤Ai<2^31
输入样例:
1 2 3
输出样例:
3
此题的关键:要求出最大异或数,该数的二进制表示中尽可能使31位上的数都为1,意味着进行异或的两个数二进制表示中第i位上的值要不相等。
思路:枚举每一个值,找出一个与之异或结果的二进制表示中每一位尽可能都是1的值。这个数就是枚举的该值与其他值异或的最大值。
(注:1<<i:将1左移i位,即让二进制中第i位为i ,res += 1<<i:让res的二进制表示中第i位加上1)
import java.util.*;
class Main{
static final int N = 100010;
static int n,idx;
static int[][] son = new int[31*N][2];//子节点
static int[] a = new int[N];
public static void main(String[] args){
Scanner in = new Scanner(System.in);
n = in.nextInt();
for(int i=0;i<n;i++)
a[i] = in.nextInt();
for(int i=0;i<n;i++)
insert(a[i]);//创建Tire树
int res = 0;
for(int i=0;i<n;i++){
res = max(res,query(a[i]));//找出最大异或数
}
System.out.println(res);
}
//插入
static void insert(int x){
int r = 0;
for(int i=30;i>=0;i--){
int t = x>>i&1;
if(son[r][t]==0)
son[r][t] = ++idx;
r = son[r][t];
}
}
//查询
static int query(int x){
int r = 0 , res = 0;
for(int i=30;i>=0;i--){
int t = x>>i&1;//t为x的二进制表示中第i位
if(son[r][1-t]!=0){//如果如果该节点的u是0,则判断一下在这一层有没有跟他相反的0-1,1-0,如果相反对应位置有数
res += 1<<i; //res就将该二进制位对应异或之后的最优解1每一位顺次加起来。因为是异或相反数就是1,这是最优解
r = son[r][1-t];//然后往最优解那边前进一层。
}
else{
//res += 0<<i;0可以省略
r = son[r][t];//然后让他往不优解那边前进一层。
}
}
return res;
}
static int max(int x,int y){
if(x>=y)
return x;
return y;
}
}