可爱的Trie树

本文介绍了Trie树(前缀树)的概念、初始化、插入和查找操作,并通过实例解析了其工作原理。同时,文章提及了在CF1446c题目中Trie树的应用,展示了如何利用Trie树解决构建树形结构的问题。
摘要由CSDN通过智能技术生成

可爱的Trie树

鉴于ducati的建议下,讲一下trie树(见书p77)

Definition 定义

—Trie又被称为前缀树、字典树,所以当然是一棵树。树中的每一条边上都标识有一个字符。这些字符可以是任意一个字符集中的字符。比如对于都是小写字母的字符串,字符集就是’a’-‘z’;对于都是数字的字符串,字符集就是’0’-‘9’;对于二进制字符串,字符集就是0和1。

初始化

  • 一棵空trie仅包含一个根节点,该点的字符指针均指向NULL

插入 Insert

  • 当需要插入一个字符串S时,我们令一个指针P起初指向根节点。然后依次扫描S中的每个字符c:
    1.若P的c字符指针指向一个已经存在的节点Q,则令P=Q。
    2.若P的c字符指针指向,则新建一个节点Q,令P的c字符指针指向Q,然后令P=Q。

非常地不好理解?让我用大白话来讲一遍:
一个字符串S(即一个单词),从左到右扫描这个单词,如果字母在相应根节点下没出现过,就插入这个字母;如果出现过,就沿着trie树往下走。单词的下一个字母也是同理。(有木有好理解一点)

查找 Search

当需要检索一个字符串S在Trie中是否存在时,我们令一个指针P起初指向根节点,然后依次扫描S中地每个字符c:

  1. 若P的c字符指针指向空,则说明S没有被插入过Trie,结束检索。
  2. 若P的c字符指针指向一个已经存在的节点Q,则令P=Q。

当S中的字符扫描完毕时,若当前节点P被标记为一个字符串的末尾,则说明S在Trie中存在,else 说明S没有被插入过Trie。

还是用大白话翻译一下:
从左往右依次扫描S中的每个字符c,顺着Trie树往下,能找到这个字母,往下走,找不到这个字母就结束查找,即没有这个前缀;前缀扫完了,表示有这个前缀。

下面代码:

//Trie

int trie[SIZE][26],tot=1; //初始化,假设字符串由小写字母构成;
void insert(char*str) {	//insert字符串; 
	int len=strlen(str),p=1;
	for (int k=0;k<len;k++)
	{
		int ch=str[k]-'a';
		if (trie[p][ch]==0)
			trie[p][ch]=++tot;
		p=trie[p][ch];
	}
	end[p]=true;
} 

bool search (char*str) { //search字符串;
	int len=strlen(str),p=1;
	for (int k=0;k<len;k++) {
		p=trie[p][str[k]-'a'];
		if (p==0)
			return false;
	} 
	return end[p];
}

当然这样讲是大不能让读者完全理解trie树的,于是举个栗子:

CF1446c

这题是ducati神犇推荐的%%%
插一个小花絮,我一开始看题的时候没有看到有翻译,对着英文看完写完的qaq(眼神不好

题意

给定你一个序列a,对于每个i,它会向序列中的满足ai⊕aj最小的j连双向边,并且如果j也向i连了边,只算一条边。现在要让你删去序列中的一些数,使得最后形成的图是一颗树,输出最少需要删除几个数。

题解

首先可以判断这是张图,而且这张图可能有环或者不连通。那我们就要使其组成的图是一棵树,就要删除一些元素。

思路说来就来:
先在每个数里插入一棵trie树,对于任意节点,若左儿子和右儿子的size都大于1,则会形成两个子图;所以我们就要删除一些节点,使其中一个儿子的size=1(这里用dp就行)。

这边放一下部分代码~~(一开始写的时候insert不会写,后来补上了就ac了qwq~~


int read()
{
	int n=0,f=-1;
	char ch;
	while((ch=getchar())<'0' || ch>'9') 
	{
		if(ch=='-')	f=-1;
	}
	while(ch>='0' && ch<='9') {
	n=(n<<3)+(n<<1)+(ch^48);
	ch=getchar();
	}
	return n*f;
}

/*void insert(int &n,int v,int d) 
当时没补就保存了所以看官自行脑部吧qaq*/ 


void dp(int n,int d)
{
	if(!n||d==0) 
		return;
	dp(ls[n], d-1);
	dp(rs[n], d-1);
	
	if(!ls[n])
		f[n]=f[rs[n]];
	else if(!rs[n])
		f[n]=f[ls[n]];
	else 
		f[n]=max(f[ls[n]],f[rs[n]])+1;
}
signed main()
{
	z=read();
	for(int i=1;i<=z;i++)
		insert(rt,read(),31);
	dp(rt,31);
	cout<<z-f[rt]<<endl;
}

trie树其实也不很难的亚子~
谢谢大家看完qwq

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值