数据结构(字典树)

本文介绍了字典树(Trie树)的实现原理及其优化,用于快速查找字符串。通过示例展示了如何插入字符串并查找出现次数。此外,还讲解了01字典树在处理异或问题中的应用,如何构建01字典树以求解最大异或值。这些数据结构在字符串搜索和位操作中具有高效性能。
摘要由CSDN通过智能技术生成

一、字典树

字典树是一种用于实现字符串快速检索的多叉树结构,又称前缀树、Trie

下面的字典树以字符串为例:

字典树的每个结点都存储有若干个指针,如果在插入或者检索的过程中,扫描(历遍)到一个字符c,就沿着当前结点的c字符指针向下走

nex数组的第一维是指针的编号,第二维是可能出现的字符(如a~z对应0~26),数组的内容存储下一个指针的编号

ans数组记录能到达该点(以到该点的字符串为前缀)的字符串的个数

send数组记录在该点结尾的字符串的个数(可以开成bool数组记录是否存在到该点的字符串)

int nex[maxn][26], cnt = 0;
int ans[maxn];
int send[maxn];
char s[20];
void insert(char* s)
{
	int len = strlen(s);
	int p = 0;
	for (int i = 0; i < len; i++)
	{
		int c = s[i] - 'a';
		if (!nex[p][c])
			nex[p][c] = ++cnt;		//如果没有,就添加结点
		p = nex[p][c];
		//ans[p]++;		//路径上的每个点都记录
	}
	send[p]++;				//以该点结尾的字符串又send[i]个
}
int finds(char* s)
{
	int len = strlen(s);
	int p = 0;
	for (int i = 0; i < len; i++)
	{
		int c = s[i] - 'a';
		if (!nex[p][c])
			return 0;
		p = nex[p][c];
	}
	return send[p];			//返回字符串出现次数
	//return ans[p];
}

优化:

1、不用string而用char数组

2、将nex数组可以改成map、ans记录可以改成unorder_map 

map<pair<int, char>, int>nex;
unordered_map<int, int>ans;
ll cnt;
char s[maxn];
void insert()
{
	int len = strlen(s);
	int p = 0;
	for (int i = 0; i < len; i++)
	{
		int c=s[i];
		if (!nex[{p, s[i]}])
			nex[{p, s[i]}] = ++cnt;		//如果没有,就添加结点
		p = nex[{p, s[i]}];
		ans[p]++;
	}
}
int query()
{
	int len = strlen(s);
	int p = 0;
	for (int i = 0; i < len; i++)
	{
		int c = s[i];
		if (!nex[{p, s[i]}])
			return 0;
		p = nex[{p, s[i]}];
	}
	return ans[p];
}

二、 01字典树

01字典树常用来处理异或的问题

把一个数转化为2进制,然后从高到低位历遍,把二进制形式当成字符串,由此来建树

int nex[maxn*32][2], nend[maxn * 32], cnt;
ll val[maxn * 32];
void insert(ll x) 
{
	int p = 0;
	for (int i = 32; i >= 0; i--) 
	{
		int u = x >> i & 1;		//从最高位开始历遍
		if (!nex[p][u])
			nex[p][u] = ++cnt;
		p = nex[p][u];
		nend[p]++;
	}
	val[p] = x;			//编号为p的值
}
ll query(ll x) 
{
	int p = 0;
	for (int i = 32; i >= 0;i--)
	{
		int u = (x >> i) & 1;
		if (nex[p][u ^ 1])	//想要求与x异或值最大的,那么尽量走与x为相异的路径
			p = nex[p][u ^ 1];
		else
			p = nex[p][u];
	}
	return val[p];
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值