Trie树

Trie树

Trie树,即字典树,是一个非常巧妙的数据结构,能够有效得优化代码的运算速度,最重要的是学习它的思想。

1.什么是Tire树?

Tire树是一种具有快速搜索特性树状数据结构,常常被单词查询系统使用。

它的特点如下:

  • 具有一个不包含任何元素的空结点作为根节点,任何搜索都从根节点开始。
  • 从根节点到某一分结点,这条路径上的与每个节点的元素组合起来就是查询结果。
  • 每个结点的子节点的元素各不相同。

我们就以用它来存单词为例:

存入单词:abandon、aboard、afterward、baby、background

存入后它的结构是这样的,每一条路都代表了一个单词:

a
b
a
n
d
o
n
o
a
r
d
f
t
e
r
w
a
r
d
b
a
b
y
c
k
g
r
o
u
n
d
root

理解了什么是tire之后,我们来看两道题。

2.Tire的应用

先来看看这道题:835. Trie字符串统计 - AcWing题库

  1. 首先是将字符串存入树中。son数组用来储存每一个结点,num数组用于储存单词的重复次数,idx用于赋值位置。
int n;
char str[N];
int son[N][26], num[N], idx;

void insert(char str[])
{
	int p = 0;
	for (int i = 0; str[i]; i++)
	{
		int u = str[i] - 'a';
		if (!son[p][u])son[p][u] = ++idx;//如果不存在结点则开辟
		p = son[p][u];//更新p值
	}
	num[p]++;//在结尾标记该字符串的数量数。
}
  1. 然后是读取出现的次数。
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;//没有符合的子节点,则返回0,表示没有存入该字符串
		p = son[p][u];//更新p值
	}

	return num[p];//返回数量
}

如此一来,问题就解决了。

Trie树当然还有其他用法,看看这题:143. 最大异或对 - AcWing题库

先用无所不能的暴力写法写写看:

for(int i = 0;i < n;i++)
    for(int j = i + 1;j < n;j++)
        ans = max(ans,a[i]^a[j]);

毫无疑问,它会TLE。那么,就要用到Trie了。

我们将这组数据用二进制形式存到Trie树中,每次对比时,如果有在这位上不同的路径就走那条路,另一条路不必访问。

  1. 数据存入:
const int N = 1e5 + 10, M = 4e6;
int son[M][2], idx;
int a[N], n;

void insert(int a)
{
	int p = 0;
	for (int i = 30; ~i; i--)//读取到i=-1时,由于-1取反为0,即可退出循环,是i >= 0的简便写法
	{
		int& s = son[p][a >> i & 1];//&是引用符号,对s赋值时son[p][a >> i & 1]的值也会改变,避免了再算一遍a >> i & 1
		if (!s)s = ++idx;
		p = s;
	}
}
  1. 数据遍历读取:
int ans = 0;
for (int i = 0; i < n; i++)ans = max(ans, query(a[i]));//循环对比每个数据的最大异或值,从而得到这组数据的最大异或值

​ query函数如下:

int query(int x)
{
	int p = 0, res = 0;
	for (int i = 30; ~i; i--)
	{
		int s = x >> i & 1;
		if (son[p][!s])//如果存在不同的值,则访问这条路径,并更新res的值
		{
			res += 1 << i;
			p = son[p][!s];
		}
		else p = son[p][s];//相同的数异或结果为0,无需更新rex值
	}
	return res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值