Trie|并查集|堆|

news2024/11/27 5:36:01

目录

初始化

插入

查询

合并集合 

连通块中点的数量 

堆排序 

 模拟堆


 

Trie树是用来快速存储和查找字符串集合的数据结构

 

#include<iostream>
using namespace std;
const int N = 100010;
int son[N][26];//本题为小写因为字母,每个节点最多有26个子节点,所以是N,26
int cnt[N];//以当前节点结尾的字符有多少个
int idx;//当前所用到的下标,下标是0的点,即使根节点,又是空节点
char str[N];
void insert(char str[])
{
	int p = 0;
	for (int i = 0; str[i]; i++)//str结尾是\0,我们这里用str[i]判断是否走到了结尾
	{
		int u = str[i] - 'a';//当前字母对应的子节点编号,把a-z,映射成0-25
		if (!son[p][u]) son[p][u] = ++idx;//如果当前p节点不存在u当前所代表的字母,我们就把它创建出来
		p = son[p][u];//走到下一个点
	}
	cnt[p]++;// 结束的时候 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 cnt[p];
}
int main()
{
	int n;
	scanf("%d", &n);
	while (n--)
	{
		char op[2];//存储操作类型
		scanf("%s%s", op, str);
		if (op[0] == 'I')
		{
			insert(str);
		}
		else
			printf("%d\n",query(str));
	}
	return 0;
}

Trie(字典树)是一种用于实现字符串快速检索的多叉树结构。Trie 的每个节点都拥有若干个字符指针,若在插入或检索字符串时扫描到一个字符 c,就沿着当前节点的 c 字符指针,走向该指针指向的节点。

Trie树可以 高效 支持 两个操作

  • 存储字符串集合
  • 查询字符串集合

有一个 经验:凡是用到Trie树的题目,一般来说给出的字符串要么全是小写字母,要么全是大写字母,要么都是数字,要么全是01,总之字母类型不是很多。

下面来看看它是如何高效存储字符串的:

初始化

一棵空Trie树 仅包含一个根节点,该点的字符指针 均指向空

插入

(1)过程分析

当需要 插入一个字符串S 时,我们令一个指针Р起初指向根节点。然后,依次扫描S中的每个字符c:

  • 1.若Pc字符指针 指向一个已经存在的节点Q,则 P= Q
  • 2.若Pc字符指针 指向空,则 新建一个节点Q,令Pc字符指针 指向Q,然后 令P=Q

s中的字符 扫描完毕时,在当前节点P上 标记它是一个字符串的末尾

下图展示了 向Trie树中插入字符串过程,每插入一个字符串 都会标记一次
在这里插入图片描述
在上图所示的例子中,需要插入和检索的字符串都由小写字母构成,所以Trie 的每个节点具有26个字符指针,分别为a到 z

上图展示了在一棵空Trie中依次插入“cab"、“cos"、"car"、“cat”、" cate” 和 “rain” 后的 Trie 的形态,灰色 标记了 单词的末尾节点

可以看出在Trie 中,字符数据都体现在树的边(指针)上树的节点仅保存一些额外信息,例如 单词结尾标记等。

(2)空间复杂度

O(NC),其中 N是节点个数(即我们想要存储的字符串的最大长度),C是字符集的大小(如:26个字母则 C = 26,Trie树中 每个节点最多向外生26条边)。

(3)时间复杂度

树的高度成正相关

(4)代码片段

const int N = 1e7+10;
inr son[N][26]; //存储Trie树中每个点所有儿子
int cnt[N]; //存储以当前这个节点结尾的单词有多少个
int idx; //当前用到了哪个下标,下标是0的节点既是根节点,又是空节点

void insert(string s)
{
    int p = 0; //从根节点开始
    for(int i=0; i<s.size(); ++i) //从前往后遍历所插字符串的每个字符
    {
        int u = s[i] - 'a'; //每次将遍历到的当前字符对应的子节点编号求出(将小写字母 a~z 映射成 0~25)
        if(!son[p][u]) son[p][u] = ++idx; //如果当前节点 p 不存在 u 这个儿子,就创建出来
        p = son[p][u]; //走到下一个点
    }
    cnt[p]++; //结束的时候 p 指向的点 对应 插入字符串的最后一个字符,表示以该点结尾的单词数量多了一个
}

查询

(1)过程分析

当需要 查询一个字符串STrie中是否存在 时,我们令一个指针Р起初指向根节点,然后依次扫描S中的每个字符c:

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

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

(2)时间复杂度

树的高度成正相关

(3)代码片段

int query(string s) //返回的值是字符串出现的次数
{
    int p=0; //从根节点开始
    for(int i=0; i<s.size(); ++i)
    {
        int u = s[i]-'a'; //每次将遍历到的当前字符对应的子节点编号求出(将小写字母 a~z 映射成 0~25)
        if(!son[p][u]) return 0; //如果当前节点 p 不存在 u 这个儿子,说明当前集合不存在这个单词,直接返回 0 即可
        p = son[p][u]; //否则的话就走到下一个点
    }
    return cnt[p]; //返回以 p 结尾的单词数量
}

合并集合 

 

 

并查集可以在近乎O(1)的时间复杂度内支持这俩个操作 

  

 合并:让一个树成为另一棵树的子树

#include<iostream>
using namespace std;
const int N = 100010;
int p[N];//存储每个元素的父节点,当p[i]=i时,i就是树根
int n,m;
int find(int x)//返回x所在集合的编号(返回x的祖宗节点)+路径压缩
{
	if (p[x] != x) p[x] = find(p[x]); 
	return p[x];
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i)
	{
		p[i] = i;//先把所有p节点的值赋成自己
	}
	while (m--)
	{
		char op[2];
		int a, b;
		scanf("%s%d%d", op,&a,&b);
		if (op[0] == 'M')
		{
			p[find(a)] = find(b);//合并操作,让A的祖宗节点成为B祖宗节点的子节点

		}
		else//判断俩节点是不是在同一集合里
		{
			if (find(a) == find(b))
			{
				puts("Yes");
			}
			else
				puts("No");
		}
	}
	return 0;
}

 如何知道当前集合个数?

连通块中点的数量 

 

把a插到b里面,之后更新size[b]即可 

#include<iostream>
using namespace std;
const int N = 100010;
int p[N],SIZE[N];//存储每个元素的父节点,当p[i]=i时,i就是树根,size[N]表示每个集合里面点的数量,只有根节点的size有意义 
int n,m;
int find(int x)//返回x所在集合的编号(返回x的祖宗节点)+路径压缩
{
	if (p[x] != x) 
p[x] = find(p[x]); //起到路径压缩的作用
	return p[x];
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i)
	{
		p[i] = i;//先把所有p节点的值赋成自己
		SIZE[i] = 1;//最开始每个集合里面只有一个点
	}
	while (m--)
	{
		char op[5];
		int a, b;
		scanf("%s", op);
		if (op[0] == 'C')
		{
			scanf("%d%d", &a, &b);
			if (find(a) == find(b))
				continue;
			SIZE[find(b)] += SIZE[find(a)];
			p[find(a)] = find(b);//合并操作,让b的祖宗节点成为a祖宗节点的子节点

		}
		else if (op[1] == '1')//询问是否在俩个集合当中Q1
		{
			scanf("%d%d", &a, &b);
			if (find(a) == find(b))
				puts("Yes");
			else
				puts("No");
		}
		else//某集合点中的数量
		{
			scanf("%d", &a);
			printf("%d\n", SIZE[find(a)]);
		}
	}
	return 0;
}

堆排序 

  

 

 

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010;
int n, m;
int h[N], SIZE;//size表示堆中当前有多少个元素
void down(int u)
{
	int t = u;//t表示左右儿子和父节点中的最小值
	if (u * 2 <= SIZE&& h[u * 2] < h[t]) t = u * 2;//如果数据在范围内,而且左儿子小于最小值,则t就是左儿子
	if (u * 2 + 1 <= SIZE && h[t] > h[u * 2 - 1]) t = u * 2 - 1;//右儿子
	if (u != t)//如果U不等于t,说明根节点就不是最小值,我们把最小值和根节点换一下即可
	{
		swap(h[u], h[t]);
		down(t);
	}

}
int main()
{
	scanf("%d%d", &n,&m);
	for (int i = 1; i <= n; ++i) scanf("%d", &h[i]);
	SIZE = n;
	for (int i = n / 2; i; i--)
	{
		down(i);
	}//从n/2开始建堆,会优化时间复杂度到O(N)
	while (m--)
	{
		printf("%d", h[1]);//打印堆顶元素
		//删除堆顶元素
		h[1] = h[SIZE];
		SIZE--;
		down(1);
	}
	return 0;
}

up操作 

void up(int u)
{
	while (u / 2 && h[u / 2] > h[u])//只要有父节点,而且当前节点大于父节点,就换上去
	{
		swap(h[u / 2], h[u]);
		u /= 2;
	}
}

 模拟堆

 

  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/429035.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JUC编程之——synchronized的底层实现与分析

1 synchronized关键字 synchronized 是 Java 中的关键字&#xff0c;是一种同步锁(也是一种悲观锁)。它修饰的对象有以下几种&#xff1a; 作用于实例方法&#xff0c;当前实例加锁&#xff0c;进入同步代码前要获得当前实例的锁——对象锁&#xff1b;作用于代码块&#xff…

水文水利数据对接详解

数据对接 水雨情监测及视频监控系统需要与什么平台进行对接&#xff1f; 答&#xff1a;水雨情监测及视频监控系统由省统一接收的方式&#xff0c;数据接收中心设在***水利云。 2.水雨情数据接收中心有哪些组成部分&#xff1f; 答&#xff1a;水雨情数据接收中心主要由硬件…

pdf如何压缩变小,pdf压缩教程四招快速学

PDF是我们日常工作中经常使用的文件格式之一。这种文件格式方便易用&#xff0c;能够确保文件在传输和接收过程中不会出现错版等问题。为了方便发送&#xff0c;我们通常会将编辑好的内容转换为PDF格式。但是有时候文件过大&#xff0c;无法通过传输渠道发送怎么办&#xff1f;…

字节5年测试工程师对“测试开发”的理解

写在前面&#xff1a; 写这篇文章的目的是为了能够更好的帮助刚入职的新人了解这个岗位和自己的工作&#xff0c;也想谈谈自己工作一年来对这个领域的了解程度&#xff0c;做一个小小总结吧&#xff5e; 一、我理解的测试开发 测试开发与开发、测试的关系 以前在没有接触测试…

樱花树盛开的季节,我用简单的C代码绘制了一棵樱花树向她表白~『C/C++图形库EasyX』

文章目录&#x1f490;专栏导读&#x1f490;文章导读绘制一根线条绘制一个简易的树干优化树干&#xff0c;使其更加细致绘制樱花树增加随机树形与渐变色效果如何设置随机数进阶——通过鼠标点击来控制生成樱花树进阶——生成樱花树并展示生长过程&#x1f490;专栏导读 &#…

通过阿里云函数计算解决ChatGPT API的调用问题

ChatGPT系列文章 与其被ChatGPT取代&#xff0c;不如征服ChatGPT&#xff0c;做它的主人&#xff01; 文章目录ChatGPT系列文章前言命令行部署准备工作两行命令实现部署应用中心部署使用代理访问API总结前言 自2022年11月30日 OpenAI 发布 ChatGPT 以来&#xff0c;虽然时有唱…

最新版本VSCode配置Python、PyQt5、QtDesigner环境并创建一个ui界面测试

参考链接&#xff1a;最新版本VSCode配置Python、PyQt5、QtDesigner环境并创建一个ui界面测试 一、安装Python3 PyQt5所支持的python版本是从3.5开始的&#xff0c;因此安装的Python3版本必须大于3.5。 我安装的位置是C:\Python\Python38。 参见真小白入门Pyhton的安装 二、安…

图-文多模态,大模型,预训练

参考老师的无敌课程 多模态任务是指需要同时处理两种或多种不同类型的数据&#xff08;如图像、文本、音频等&#xff09;的任务。例如&#xff0c;图像描述&#xff08;image captioning&#xff09;就是一种典型的多模态任务&#xff0c;它需要根据给定的图像生成相应的文本描…

XO08R2 1SBP260109R1001接地系统能够为dcs提供屏蔽层,消除电子噪声干扰

​ XO08R2 1SBP260109R1001接地系统能够为dcs提供屏蔽层&#xff0c;消除电子噪声干扰 dcs合理、可靠的系统接地&#xff0c;是dcs系统非常重要的内容。为了保证dcs系统的监测控制精度和安全、可靠运行&#xff0c;必须对系统接地方式、接地要求、信号屏蔽、接地线截面选择、接…

【C++学习】map和set的封装

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《C学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; map和set的封装&#x1f349;map和set中的红黑树&#x1f34c;set中的键值和map中的键值&#x1f349…

CTF杂项提纲

CTF的杂项是涉及编码&#xff0c;图片隐写&#xff0c;音频隐写&#xff0c;压缩包分析的方向&#xff0c;本文对MISC的知识点做了一个简单列举 常见编码 ASCII 0-9,48-57 A-Z 65-90 a-z 97-122 URL url编码又叫百分号编码&#xff0c;是统一资源定位的编码方式 base16/…

ModStartCMS v6.2.0 VIP权益配置功能,界面UI优化升级

ModStart 是一个基于 Laravel 模块化极速开发框架。模块市场拥有丰富的功能应用&#xff0c;支持后台一键快速安装&#xff0c;让开发者能快的实现业务功能开发。 系统完全开源&#xff0c;基于 Apache 2.0 开源协议&#xff0c;免费且不限制商业使用。 功能特性 丰富的模块市…

【初识数据库】数据库简介及MySQL安装

目录 数据库基本概念&#xff1a; 主流的关系型数据库&#xff1a; 下载并安装数据库 我们选择的是&#xff1a;MySQL Community Server 8.0.26 卸载老版本MySQL 数据库基本概念&#xff1a; 数据库&#xff1a;是数据的仓库&#xff0c;存储数据的地方 数据库管理系统&am…

RK3568平台开发系列讲解(调试篇)debugfs 分析手段

🚀返回专栏总目录 文章目录 一、enable debugfs二、debugfs API三、使用示例沉淀、分享、成长,让自己和他人都能有所收获!😄 📢Linux 上有一些典型的问题分析手段,从这些基本的分析方法入手,你可以一步步判断出问题根因。这些分析手段,可以简单地归纳为下图: 从这…

进程虚拟地址空间的划分

进程虚拟地址空间划分是操作系统中的一个核心概念&#xff0c;它决定了进程可以访问的内存范围和方式。在本文中&#xff0c;我们将介绍进程虚拟地址空间的划分方法和各个部分的作用。 进程虚拟地址空间的划分方法 在操作系统中&#xff0c;每个进程都有自己的虚拟地址空间&am…

到底还是留不住!库克“中国行”后火速变脸,3000亿产能转向印度?

以国家的层面来制衡一家科技企业&#xff0c;这种事或许只有老美干得出来。当看到华为即将崛起之时&#xff0c;美一意孤行&#xff0c;修改了大量关乎芯片和商贸的政策。层层围堵之下&#xff0c;华为如今的市场份额大幅缩水&#xff0c;腾出来的高端市场基本被苹果占据。相关…

2023年数据挖掘与知识发现国际会议(DMKD 2023) | IOP JPCS独立出版

会议简介 Brief Introduction 2023年数据挖掘与知识发现国际会议(DMKD 2023) 会议时间&#xff1a;2023年6月24日-26日 召开地点&#xff1a;中国重庆 大会官网&#xff1a;DMKD 2023-2023 International Conference on Data Mining and Knowledge Discovery 由重庆邮电大学、重…

找工作吗?50道Python面试题集锦【附答案】

嗨害大家好鸭&#xff01;我是爱摸鱼的芝士~ 希望能够帮助你在今年的求职面试中脱颖而出&#xff0c; 找到一份高薪工作~ 这些面试题涉及Python基础知识、Python编程、数据分析以及Python函数库等多个方面。 提前预祝给这篇文章点赞收藏的友友们~ 拿到心中最满意的那一份OF…

PHP快速入门13-MySQL数据库与Redis操作

文章目录前言一、PHP连接MySQL1.1 建立数据库链接1.2 插入数据1.3 更新数据1.4 删除数据1.5 查询数据并输出结果1.6 查询数据并返回结果1.7 获取查询结果的行数1.8 获取查询结果的列数1.9 获取查询结果的字段名1.10 获取查询结果的字段类型1.11 获取上一次操作影响的行数1.12 开…

PsExec流量分析

PsExec远程连接服务器 psexec是sysinternals提供的众多windows工具中的一个&#xff0c;这款工具的初衷是帮助管理员管理大量的机器的&#xff0c;后来被攻击者用来做横向渗透。 下载地址&#xff1a; https://docs.microsoft.com/en-us/sysinternals/downloads/psexec使用Ps…