Java / Scala - Trie 树简介与应用实现
目录
一.引言
二.Tire 树简介
1.树 Tree
2.二叉搜索树 Binary Search Tree
3.字典树 Trie Tree
3.1 基本概念
3.2 额外信息
3.3 结点实现
3.4 查找与存储
三.Trie 树应用
1.应用场景
2.Java / Scala 实现
2.1 Pom 依赖
2.2 关键词匹配
四.总结
一.引言
Trie 树即字典树,又称为单词查找树或键树,是一种树形结构,常用于统计,排序和保存大量的字符串,所以经常被搜索引擎系统用于文本词频统计。
◆ 优点 - 利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
◆ 思想 - 其核心思想是空间换时间,通过拆分字符串并存储换取查询的高效率
二.Tire 树简介
1.树 Tree

上面是最常见的树的形态,其拥有根节点 root,有左右的 sub-tree 子树,每个父结点 Parent Node 可能拥有子节点 Child Node,也有可能没有子节点,此时为 None。Siblings 代表同级的兄弟姐妹节点,Level 代表树的深度即层数。
2.二叉搜索树 Binary Search Tree

二叉搜索树(Binary Search Tree,简称 BST),又被称为二叉查找树、排序二叉树,是指一个空树或者具备下列性质的二叉树:
◆ 若任意节点的左子树不为空,则左子树上所有节点的值都小于它的根节点的值。
◆ 若任意节点的右子树不为空,则右子树上所有节点的值都大于它的根节点的值。
◆ 任意节点的左、右子树也分别为二叉搜索树。
◆ 没有键值相等的节点(即相同的元素只能出现一次)。
其具备以下特性:
◆ 中序遍历 - 对 BST 进行中序遍历会得到一个有序的序列。这是因为在中序遍历的过程中,先访问左子节点(较小),再访问当前节点,最后访问右子节点(较大)。
◆ 查找效率 - 在 BST 中查找一个元素的平均时间复杂度和树的深度有关,理想情况下,即 BST 是平衡的时候,时间复杂度是 O(log n),其中 n 是树中节点的数量。但是在最坏情况下,如树完全不平衡(退化成链表),查找时间复杂度退化为O(n)。
◆ 插入和删除操作 - 插入和删除也有可能改变树的结构。BST 的插入操作是指在满足上述性质的情况下,将一个新节点插入到树中。删除操作则可能涉及到重新调整树的结构,以保持二叉搜索树的性质。
3.字典树 Trie Tree
3.1 基本概念

注意这里 Trie 树不是二叉树,而是一颗多叉树,具体分多少叉要根据我们的实际场景来定。例如我们 Trie 树要存储所有英文单词,那理论上每一个父结点 Parent Node 要分 26 个子节点 Child Node,因为英文有 26 个英文字母。Trie 树具备如下基本性质:
◆ 结构本身不存储完整单词,而是存储每个细粒度的拆分项,例如单词搜索则存储字母
◆ 结从根结点到某一结点,将路径上的字符相连,为该结点对应的字符串
◆ 每个结点的所有子结点路径代表的字符都不相同,这里其实代表没有重复字符串结点
3.2 额外信息

每个 Node 结点除了存储对应的字符外,其还可以具备其自己的属性,最简单的,上面的示例中给出了对应字符串的出现频次,这可以作为搜索推荐的参考依据,如果是代码,其额外信息可以作为一个 Class 存在,内部包含该节点多个属性,例如字符串对应的领域、频率、长度、适用范围等等。 说到词频,也让我们想起来 Word2vec 里用到的霍夫曼树,其在构造编码时也考虑了词频的因素,使得词频高的词可以尽可能快的找到。
3.3 结点实现

这里对于每个 Node 而言,结点就不存在 Left 和 Right 的概念了,而是直接对应下一个可能的字符串,选定哪个字符串,就到下一个字符串对应的 Node 上。如果我们认为是简单单词且不区分大小写,我们可以认为每个 Node 最多有 26 个分叉结点,但如果有更多字符或特殊符号的加入,那么多叉树会有更多的分叉。如果一个结点指向 null 代表其没有儿子结点,此时连接其路径上的字符即可得到该结点对应的字符串表示。
3.4 查找与存储
◆ 存储
假设是上面提到的英文单词查找,且不区分大小写,此时最坏的情况为 26 叉树,每分叉一次,一个结点就多 26 个叉,这样的指数分叉对于存储空间还是有很大的消耗。
◆ 查找

相比于存储的消耗,查找的速度会快很多,因为查找的次数是和单词的字符量匹配的,常见的英文单词字符量在 10 左右,那我们只需要 10 次的常数时间就可以查到,以 you 为例,只需要 3 步就可以找到。但如果是用二分查找等方法,由于整个字典集的数量 n 特别大,即使排好序也是 Log(n) 的查找效率,会比 Trie 树查找次数多很多。这也体现了我们开头说的 Trie 树的核心思想: 空间换时间。其实这个概念不光是 Trie 树,很多算法都会用到这个思想,将时间复杂度降低,空见复杂度提升。
三.Trie 树应用
1.应用场景

因为 Trie 树公共前缀的使用, 所以它十分适合搜索与输入法拓展等领域,当我们输入了前面的公共前缀,其可以根据词频很容易的给出后面的候选。 实际场景中应用较多的是 Aho-Corasick 算法,其适用于确定性的、完全匹配的字符串搜索场景,它能够高效地检测出预定义的关键词是否在给定文本中出现。针对每一次输入,算法都能找出所有存在的关键词匹配。
2.Java / Scala 实现
2.1 Pom 依赖
<!-- https://mvnrepository.com/artifact/org.ahocorasick/ahocorasick --><dependency><groupId>org.ahocorasick</groupId><artifactId>ahocorasick</artifactId><version>0.6.3</version></dependency>
2.2 关键词匹配
import org.ahocorasick.trie.{Emit, Token, Trie}// 初始化并构建Trieval trie = Trie.builder().addKeyword("hers").addKeyword("his").addKeyword("she").addKeyword("he").build()// 搜索文本val text = "she sells sea shells by the sea shore"// 执行搜索val tokens: java.util.Collection[Token] = trie.tokenize(text)// 注意这里使用Java转Scala的集合转换import scala.collection.JavaConverters._for (token <- tokens.asScala) {if (token.isMatch) {// 打印匹配的词条和位置println(s"Found match: ${token.getFragment} at position ${token.getEmit.getStart}")}}
- addKeyword 用于添加关键词到 Trie 树中
- text 为代分析的文本
- tokenize 方法分析文本进行关键词匹配
- isMatch getFragment 获取命中的关键词,getEmit.getStart 与 getEnd 用于获取 Fragment 片段在 text 中的起始位置

实战场景下,Builder 过程中会添加一个很大的字典内容构造 Trie 树,随后应用 Trie 树进行文本的关键词匹配,判断目标文本是否命中字典中给定的关键字。
四.总结
上面就是 Trie 树的简单介绍与应用。如果想要开发类似 Google 的关键词搜索推荐系统要比使用简单的 Aho-Corasick 算法要复杂得多,并且可能需要依赖机器学习和大数据处理技术。 如果你只是想实现一个简单版本的搜索推荐系统,可以考虑一些基础的模糊匹配算法或使用现有的搜索引擎库,比如 Elasticsearch,它内置了自动补全和模糊匹配的功能,同时 Elasticsearch 也能够通过集群分布式架构来处理大规模数据集,非常适用于构建搜索推荐系统。
相关文章:
Java / Scala - Trie 树简介与应用实现
目录 一.引言 二.Tire 树简介 1.树 Tree 2.二叉搜索树 Binary Search Tree 3.字典树 Trie Tree 3.1 基本概念 3.2 额外信息 3.3 结点实现 3.4 查找与存储 三.Trie 树应用 1.应用场景 2.Java / Scala 实现 2.1 Pom 依赖 2.2 关键词匹配 四.总结 一.引言 Trie 树…...
JS/jQuery 获取 HTTPRequest 请求标头?
场景:在jquery封装的ajax请求中,默认是异步请求。 需要定一个秘钥进行解密,所以只能存放在请求头中。然后需要值的时候去请求头中读取。 注意:dataType设置,根据请求参数的格式设置,如果是加密字符串&…...
Leetcode—2034.股票价格波动【中等】
2023每日刷题(五十二) Leetcode—2034.股票价格波动 算法思想 实现代码 class StockPrice { public:int last 0;multiset<int> total;unordered_map<int, int> m;StockPrice() {}void update(int timestamp, int price) {if(m.count(time…...
【Linux】diff命令使用
diff命令 是一个用于比较两个文件或目录之间差异的命令。它可以显示两个文件之间的行级别差异,并以易于阅读的格式输出结果。 著者 由保罗艾格特、迈克海特尔、大卫海耶斯、理查德史泰尔曼和Len Tower撰写。 diff命令 -Linux手册页 语法 diff [选项] [文件1]…...
讯飞星火认知大模型与软件测试结合,提升软件质量与效率
随着人工智能技术的不断发展,越来越多的企业开始将其应用于软件开发过程中。其中,讯飞星火认知大模型作为一种基于深度学习的自然语言处理技术,已经在语音识别、机器翻译、智能问答等领域取得了显著的成果。而在软件测试领域,讯飞…...
【Flink on k8s】- 4 - 在 Kubernetes 上运行容器
目录 1、准备 k8s 集群环境、Docker 环境 2、启用 kubernetes 2.1 查询 k8s 集群基本状态...
软件重装或系统重装后避免重复踩坑
1. Office软件的坑在于字体又没了 Word字体库默认没有仿宋_GB2312和楷体仿宋_GB2312,需要手动添加。 提供如下两个下载链接,亲测有效: 仿宋_GB2312 楷体_GB2312 安装步骤:解压-复制.ttf文件至C:\Windows\Fonts 持续更新贴~...
【Jmeter】JSON Extractor变量包含转义字符,使用Beanshell脚本来消除
如果使用Jmeter的JSON Extractor提取的变量包含特殊字符,直接引用时会包含转义字符。可以使用Beanshell脚本来进行字符串转换,从而消除这些转义字符。 import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONArray; import com.ali…...
GO设计模式——5、建造者模式(创建型)
目录 建造者模式(Builder Pattern) 建造者模式的核心角色 优缺点 使用场景 注意事项 代码实现 建造者模式(Builder Pattern) 建造者模式(Builder Pattern)是将一个复杂对象的构建与它的表示分离&…...
《LeetCode力扣练习》代码随想录——字符串(反转字符串II---Java)
《LeetCode力扣练习》代码随想录——字符串(反转字符串II—Java) 刷题思路来源于 代码随想录 541. 反转字符串 II 模拟过程 class Solution {public String reverseStr(String s, int k) {if(s.length()1){return s;}char[] chs.toCharArray();for(int i…...
WMMSE方法的使用笔记
标题很帅 原论文的描述WMMSE的简单应用 无线蜂窝通信系统的预编码设计问题中,经常提到用WMMSE方法设计多用户和速率最大化的预编码,其中最为关键的一步是将原和速率最大化问题转化为均方误差最小化问题,从而将问题由非凸变为关于三个新变量的…...
MySQL核心知识点整理大全1-笔记
目录 MySQL 一、MySQL的基本概念 1.数据库 2.表 3.列 4.行 5.主键 6.索引 二、MySQL的安装与配置 1.下载MySQL安装包 2.安装MySQL 3.启动MySQL 4.配置MySQL a.设置监听端口和IP地址 b.设置数据存储路径 c.设置字符集和排序规则 5.测试MySQL 三、MySQL的基本操…...
理解输出电压纹波和噪声:来源与抑制
医疗设备、测试测量仪器等很多应用对电源的纹波和噪声极其敏感。理解输出电压纹波和噪声的产生机制以及测量技术是优化改进电路性能的基础。 1:输出电压纹波 以Buck电路为例,由于寄生参数的影响,实际Buck电路的输出电压并非是稳定干净的直流…...
uni-app 微信小程序之好看的ui登录页面(二)
文章目录 1. 页面效果2. 页面样式代码 更多登录ui页面 uni-app 微信小程序之好看的ui登录页面(一) uni-app 微信小程序之好看的ui登录页面(二) uni-app 微信小程序之好看的ui登录页面(三) uni-app 微信小程…...
Textual Inversion
参考博客1:https://www.bilibili.com/read/cv25430752/...
笙默考试管理系统-MyExamTest----codemirror(47)
笙默考试管理系统-MyExamTest----codemirror(44) 目录 笙默考试管理系统-MyExamTest----codemirror(44) 一、 笙默考试管理系统-MyExamTest----codemirror 二、 笙默考试管理系统-MyExamTest----codemirror 三、 笙默考试…...
JVM中 Minor GC 和 Full GC 的区别
Java中的垃圾回收(Garbage Collection, GC)是自动内存管理的一部分,其主要职责是识别并清除程序中不再使用的对象来释放内存。Java虚拟机(JVM)在运行时进行垃圾回收,主要分为两种类型:Minor GC和…...
二十一章(网络通信)
计算机网络实现了多台计算机间的互联,使得它们彼此之间能够进行数据交流。网络应用程序就是在已连接的不同计算机上运行的程序,这些程序借助于网络协议,相互之间可以交换数据。编写网络应用程序前,首先必须明确所要使用的网络协议…...
[linux运维] 利用zabbix监控linux高危命令并发送告警(基于Zabbix 6)
之前写过一篇是基于zabbix 5.4的实现文章,但是不太详细,最近已经有两个小伙伴在zabbix 6上操作,发现触发器没有str函数,所以更新一下本文,基于zabbix 6 0x01 来看看效果 高危指令出发问题告警: 发出邮件告…...
手机升级到iOS15.8后无法在xcode(14.2)上真机调试
之前手机是iOS14.2的系统,在xcode上进行真机测试运行良好,因为想要使用Xcode的Instruments功能,今天将系统更新到了iOS15.8 ,结果崩了 说是Xcode和手机系统不兼容不能进行真机测试。在网上查了好些方法,靠谱的就是下载相关版本的…...
医疗陪护管理系统:信息化管理在医院的应用
博主介绍: 所有项目都配有从入门到精通的安装教程,可二开,提供核心代码讲解,项目指导。 项目配有对应开发文档、解析等 项目都录了发布和功能操作演示视频; 项目的界面和功能都可以定制,包安装运行…...
爆款AI写教材工具登场!一键生成低查重教材,轻松开启编写之旅
编写教材的困境与AI的解决方案 在编写教材时,如何准确地满足多样化的需求呢?不同年级的学生在认知能力上存在显著差异,教材内容若过于深奥或过于简单都无法达到效果;而课堂教学和自主学习等不同的环境对教材的要求各不相同&#…...
新手入门实战:从零复现简易情绪记录站,掌握Web开发基础
最近在自学前端开发,想找个简单又有趣的练手项目。发现情绪记录网站是个不错的切入点,既能练习基础技能,又能做出实用功能。今天就用InsCode(快马)平台复现了一个简易版,分享下实现过程和心得。 项目构思 这个"私密树洞"…...
linux内核故障分析及调测工具使用能力
Linux内核的故障分析和调测工具非常丰富,根据使用场景大致可以分为静态分析/代码检查、动态跟踪、性能分析、内存调试、以及崩溃转储分析这几大类。 下面我为你整理了典型工具的归类表,方便快速查阅,后面再详细解读几个核心工具的实战能力。 …...
MxRadioRF2xx库:ARM Mbed平台RF2xx射频驱动开发指南
1. MxRadioRF2xx 库概述 MxRadioRF2xx 是一个专为 ARM Mbed OS 平台设计的 Atmel(现 Microchip)RF2xx 系列射频收发器驱动库。该库并非对底层寄存器操作的简单封装,而是面向嵌入式无线应用开发者的工程化抽象层,其核心目标是&…...
AT32F435_437_USB_MSC_SDIO:实现高效SD卡U盘功能的开发指南
1. 从零开始:AT32F435/437的USB MSC功能初探 第一次接触AT32F435/437的USB大容量存储设备(MSC)功能时,我完全被它的实用性惊艳到了。想象一下,你的嵌入式设备突然变身成电脑上的U盘,可以直接拖拽文件读写SD卡,这对数据…...
STM32F103 LoRa物理层驱动库详解与工程实践
1. 项目概述LoRa_STM32 是一个面向 STM32F103CB 微控制器平台的 LoRa 通信库,本质是 sandeepmistry/arduino-LoRa 库在 STM32 平台上的适配分支。它并非独立开发的全新协议栈,而是通过 Arduino Core for STM32(rogerclarkmelbourne/Arduino_S…...
猫抓浏览器插件:网页资源嗅探与下载的终极解决方案
猫抓浏览器插件:网页资源嗅探与下载的终极解决方案 【免费下载链接】cat-catch 猫抓 chrome资源嗅探扩展 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 你是否曾在浏览网页时,看到精彩的视频、音频或图片资源,却苦于无…...
别再用ls了!从Linux文件系统卡顿,看透MinIO多级目录的性能陷阱与正确用法
从Linux文件系统卡顿到MinIO性能陷阱:高效查询的工程哲学 当你在Linux终端输入ls命令后,系统突然卡死——这种经历对许多开发者来说并不陌生。但很少有人意识到,同样的性能陷阱正潜伏在MinIO这类对象存储系统的日常使用中。本文将揭示文件系…...
避开Codesys电子凸轮Cam表设置的3个常见坑:SMC_CAMXYVA结构体赋值与MC_CAM_REF实例化详解
Codesys电子凸轮Cam表实战避坑指南:从结构体赋值到功能块调优 在工业自动化领域,电子凸轮技术正在逐步取代传统的机械凸轮系统。作为Codesys平台下的核心运动控制功能,Cam表的正确配置直接关系到设备运行的精度和稳定性。本文将深入剖析手动编…...

