前缀树概念

news/2024/10/22 19:09:20/

前缀树(prefix tree)
准备一个Str[],数组中元素有[“abc”,“bcd”,“abg”,“bcde”,“qwe”],如何将数组中元素加到树中呢?
从最开始的字符串abc说,第一个字符是a,从一个空的头节点出发,看有没有走向a字符的路,没有,就创建一条,字符不放在节点上,字符永远在路上,b也同理,从a节点出发,没有b的就创建,最终创建出来的就是下图这样。
在这里插入图片描述
后面的字符串原理相同,从头节点出发,看有没有走向该字符的路,有就复用没有则创建,所以根据上面的数组构建出来的前缀树是这样的。
在这里插入图片描述
所以可以看出来,前缀树是一课多叉树
因为前缀树中,节点不存放值,所以封装一些额外的信息属性,比如说pass(构建树的过程中,该节点经过几次),end(当前节点,有多少字符串以它结尾)。根据上面数组中的例子,算下来每一节点的情况是这样。

树构建完之后,就可以根据这个树的结构查看是否以xxx开头的字符串,以及树中是否存在xxx字符串。
在这里插入图片描述

所以说,前缀树的结构,比hash表结构强的地方就在于,前缀树可以查找树中是否存在以xxx开始的前缀字符串。

Hash表
之前的帖子中说过,hash表的增删改查都是O(1)的常数时间操作,但前提是不考虑单样本量大小的情况下。
如果说添加的都是32位的整型Int类型数字,那不用考虑,但如果添加的是一个很大的字符串(这个字符串存着一本书的内容)。那此时就不是O(1)的长度。是O(K)的操作(K = 字符串长度)。
所以说,如果往Hash表中添加数据,如果单样本大小无足轻重,则认为是O(1),如果单样本很大,那就不是O(1),因为Hash表会遍历字符串的长度计算出Hash值才知道自己再hash表中如何组织,添加100W个字符串,平均长度是100,那Hash表单次添加就是O(100)的复杂度。
添加对象也是O(1)操作,因为添加的是对象内存地址。

Java代码实现

public static class Node {private int pass;private int end;private Node[] nexts;//private HashMap<Integer,Node> nexts;public Node() {pass = 0;end = 0;//表达下层有多少路//先以26个小写英文字母为例,所以长度为26 a - z//用底层节点是否为null,标记这条路是否存在。// 0   a// 1   n// 2   c//25   z//nexts[i] == null  i方向的路不存在//nexts[i] != null  i方向的路存在nexts = new Node[26];//如果字符种类多,则用上面的hashMap存储,key 就是字符的ascII转成数字的形式。}}public static class Trie {private Node root;public Trie() {root = new Node();}//遍历,将字符拆开,挂在树上public void insert(String str) {if (str == null) {return;}char[] tmp = str.toCharArray();Node node = root;node.pass++;int path = 0;//遍历字符for (int i = 0; i < tmp.length; i++) {//通过 - 'a' 来判断下一节点是否存在,如果存在下标是什么path = tmp[i] - 'a';if (node.nexts[path] == null) {node.nexts[path] = new Node();}node = node.nexts[path];node.pass++;}node.end++;}//查询str在树中加入过几次public int search(String str) {if (str == null) {return 0;}char[] tmp = str.toCharArray();Node node = root;int path = 0;for (int i = 0; i < tmp.length; i++) {path = tmp[i] - 'a';if (node.nexts[path] == null) {return 0;}node = node.nexts[path];}return node.end;}//树中有多少以str作为前缀的public int prefixNumber(String str) {if (str == null) {return 0;}Node node = root;char[] tmp = str.toCharArray();int path = 0;for (int i = 0; i < tmp.length; i++) {path = tmp[i] - 'a';if (node.nexts[path] == null) {return 0;}node = node.nexts[path];}return node.pass;}//删除树中str字符串public void delete(String str) {//先确定要删除的字符串在树中存在,要不减完发现不存在就淦了if (search(str) != 0) {char[] tmp = str.toCharArray();Node node = root;node.pass--;int path = 0;for (int i = 0; i < tmp.length; i++) {path = tmp[i] - 'a';if (--node.nexts[path].pass == 0){//避免内存泄漏,先--,如果是0,则后面的直接都干掉。node.nexts[path] = null;return;}node = node.nexts[path];}node.end--;}}}

http://www.ppmy.cn/news/100794.html

相关文章

微服务架构之RPC调用

在单体应用时&#xff0c;一次服务调用发生在同一台机器上的同一个进程内部&#xff0c;也就是说调用发生在本机内部&#xff0c;因此也被叫作本地方法调用。在进行服务化拆分之后&#xff0c;服务提供者和服务消费者运行在两台不同物理机上的不同进程内&#xff0c;它们之间的…

基于hdoop的短视频用户画像研究_kaic

基于hadoop的短视频用户画像研究 摘 要 在这个互联网迅速发展的时代&#xff0c;网络和信息技术都跟上了时代的潮流&#xff0c;在互联网中的用户数据也出现了爆炸性的增长。用户的各种日常行为都通过互联网被记录下来&#xff0c;对于所有的互联网企业来说&#xff0c;想要从…

剑指 Offer 39. 组合总和解题思路

文章目录 题目解题思路 题目 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数…

Java设计模式系列--单例模式(破坏单例的方法)

原文网址&#xff1a;Java设计模式系列--单例模式(破坏单例的方法)_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍Java破坏单例模式的方法。 单例模式&#xff08;Singleton Pattern&#xff09;是指确保一个类只有一个实例&#xff0c;并提供一个全局访问点。破坏单例模式…

【Bug 全解决】 Java、Spring boot 后端项目 Bug 总结

Bug 收集与总结 本文记录的是 SpringBoot 后端项目使用和运行代码时所遇到的各种问题&#xff0c;全部都已解决&#xff0c;欢迎在评论区补充你遇到的 Bug 哦&#xff01;仅以本文记录学习社区项目时&#xff0c;所遇到的奇奇怪怪的 bug&#xff0c;以及一些很愚蠢的错误&…

c#快速入门

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;题目大解析2 目录 &#x1f449;&#x1f3fb; c#和c不同之处&#x1f449;&#x1f3fb;程序文件的…

Flink 快速上手,实操记录

目录 Flink 快速上手安装编写 Flink 程序总结 Flink 快速上手 Apache Flink 是一个开源的流处理框架&#xff0c;它提供了高效、可扩展、分布式的数据处理能力。本文将介绍如何快速上手 Flink。 安装 Flink 可以在官网上下载二进制包&#xff0c;也可以通过 Maven 或 Gradle…