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 也能够通过集群分布式架构来处理大规模数据集,非常适用于构建搜索推荐系统。

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

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

相关文章

【ClickHouse】ClickHouse与MySQL之间实时同步数据(MySQL引擎),将MySQL数据实时同步到clickhouse

参考1:MySQL(通过该配置实现了实时同步) 参考2:experimental MaterializedMySQL 参考3:[experimental] MaterializedMySQL(包含设置 allow_experimental_database_materialized_mysql) MySQL引擎用于将远程的MySQL服务器中的表映射到ClickHouse中&#xff0c;并允许您对表进行I…

item_get_app_pro-根据ID取商品详情原数据接入参数和返回值说明

参数说明 pinduoduo.item_get_app_pro 公共参数 名称类型必须描述keyString是调用key&#xff08;申请调用免费测试&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_shop等]cache…

JavaEE之多线程编程:1. 基础篇

文章目录 一、关于操作系统一、认识进程 process二、认识线程三、进程和线程的区别&#xff08;重点&#xff01;&#xff09;四、Java的线程和操作系统线程的关系五、第一个多线程编程 一、关于操作系统 【操作系统】 驱动程序&#xff1a; 如&#xff1a;我们知道JDBC的驱动程…

20 套监控平台统一成 1 套 Flashcat,国泰君安监控选型提效之路

author:宋庆羽-国泰君安期货 运维工作最重要的就是维护系统的稳定性&#xff0c;其中监控是保证系统稳定性很重要的一环。通过监控可以了解系统的运行状态&#xff0c;及时发现问题和系统隐患&#xff0c;有助于一线人员快速解决问题&#xff0c;提高业务系统的可用时长。 作为…

C++联合体union

联合体 将多个类型合并到一起省空间 枚举与联合一起使用 匿名联合 类似于无作用域 &#xff23;11联合体定义非内建类型 C11 引入了能够在联合体中使用非内建类型的能力&#xff0c;这些类型包括具有自定义构造函数、析构函数、拷贝构造函数和拷贝赋值运算符的类。 关键特性…

【C语言快速学习基础篇】之二控制语句、循环语句

文章目录 一、控制语句1.1、if...else...单条件语句1.2、if...else if...else...多条件语句1.3、switch...case 二、循环语句2.1、for循环2.2、while循环2.3、注意&#xff1a;for循环和while循环使用上面等同2.4、do while循环2.4.1、while条件成立时2.4.2、while条件不成立时…

BluetoothDevice 序列化问题

文章目录 前言思考分析定位 前言 在做蓝牙设备通信时&#xff0c;遇到一个奇葩的问题&#xff0c;公司另一个部门开发的蓝牙组件库&#xff0c;把蓝牙设备BluetoothDevice进行了序列化&#xff0c;在连接时候又进行反序列化。但是当我去调试我的项目时&#xff0c;发现发序列化…

P1160 队列安排

这很明显是一个链表的题目&#xff0c;考链表的基础知识 开始先定义了一个结构体节点&#xff0c;里面有一个val和一个指向node结构体的指针next 然后通过typedf将linkedlist表示为一个指向node的指针 insert代表右插入 push是左插入 #include <iostream> using nam…

[足式机器人]Part2 Dr. CAN学习笔记-自动控制原理Ch1-3燃烧卡路里-系统分析实例

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-自动控制原理Ch1-3燃烧卡路里-系统分析实例 1. 数学模型2. 比例控制 Proprotional Control 1. 数学模型 2. 比例控制 Proprotional Control

建筑工程企业网站建设的效果如何

建筑工程团队也是市场重要的组成部分&#xff0c;尤其是建筑公司&#xff0c;往往更具品牌力&#xff0c;而在企业发展方面也面临多个痛点&#xff1a; 1、品牌宣传拓客难 建筑工程属于高价、长时间跟进的行业&#xff0c;因此无论需求者还是商家都非常看重企业品牌及业务纵深…

基于ssm端游账号销售管理系统论文

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对端游账号销售信息管理混乱&#xff0c;出错率高&#xff0c;信息安全…

让你从此不再惧怕ANR

原文链接 让你从此不再惧怕ANR 这篇文章是基于官方的Diagnose and fix ANRs翻译而来&#xff0c;但也不是严格的翻译&#xff0c;原文的内容都在&#xff0c;又加上了自己的理解以及自己的经验&#xff0c;以译注的形式对原文的作一些补充。 当一个Android应用的UI线程被阻塞时…

[排序篇] 冒泡排序

目录 一、概念 二、冒泡排序 2.1 冒泡降序(从大到小排序) 2.2 冒泡升序(从小到大排序) 三、冒泡排序应用 总结 一、概念 冒泡排序核心思想&#xff1a;每次比较两个相邻的元素&#xff0c;如果它们不符合排序规则&#xff08;升序或降序&#xff09;则把它们交换过来。…

大致人类应该是短时记忆和利用短时记忆控制利用周围环境达到长期记忆的吧

这里写目录标题 图代码代码解析图 代码 import timedef route_llm(route_text):passdef write_to_dask(one_sum, one_text, one_path

小程序嵌套H5

小程序嵌套H5 使用Hbuild x开发H5页面项目里面使用了js-sdk工具包H5发布完成之后生成URL。新建一个小程序空项目&#xff0c;填写小程序的appid。本地调试的时候如果报错无法打开该网页&#xff0c;那么需要勾选先的不校验。发布体验版本需要注意下面的两个配置点。 使用Hbuild…

中通快递单号查询入口,将指定某天签收的单号筛选出来

批量查询中通快递单号的物流信息&#xff0c;将指定某天签收的单号筛选出来。 所需工具&#xff1a; 一个【快递批量查询高手】软件 中通快递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;并登录 步骤2&#xff1a;点击主界面左…

编译 Flink代码

构建环境 JDK1.8以上和Maven 3.3.x可以构建Flink&#xff0c;但是不能正确地遮盖某些依赖项。Maven 3.2.5会正确创建库。所以这里使用为了减少问题选择 Maven3.2.5版本进行构建。要构建单元测试&#xff0c;请使用Java 8以上&#xff0c;以防止使用PowerMock运行器的单元测试失…

求职智能分析系统

本项目是一个基于Flask轻量级框架的计算机就业数据可视化分析平台。 采用echarts和ajax等技术进行数据展示和用户交互。

【电路笔记】-电位器

电位器 文章目录 电位器1、概述2、电位器类型2.1 旋转电位器2.2 滑块电位器2.3 预设和微调电位器2.4 变阻器 3、电位器示例14、电位器作为分压器5、电位器示例26、变阻器6、滑块变阻器7、线性或对数电位器8、总结 当连接的轴物理旋转时&#xff0c;电位计和变阻器的电阻值会发生…

一个简单的Wireshark和TCP三次握手,为什么能难住阿里6年测试?

之前写过一篇博客&#xff1a;用 Fiddler 来调试HTTP&#xff0c;HTTPS。 这篇文章介绍另一个好用的抓包工具wireshark&#xff0c; 用来获取网络数据封包&#xff0c;包括http,TCP,UDP&#xff0c;等网络协议包。 记得大学的时候就学习过TCP的三次握手协议&#xff0c;那时候…