前缀树及其实现解析

前缀树

前缀树:又称单词查找树或键树,是一种哈希树的变种。

典型应用是用于统计和排序大量的字符串(但不仅限于字符串)

利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较。

将一组字符串数组放入前缀树中的演示

String[] str = {"abc", "bck", "abd", "ace"};

从root头节点开始,将每个字符串放入树中。

在放入第一个字符串第一个字符‘a’的时候,看头节点中有没有a的路径,如果没有,就创建;如果有,就沿着a的路径走

因此在放入字符‘b’、‘c’的时候,都创建新的路径


在放入第二个字符串的时候,依旧是从头节点开始。此时头节点没有b的路径,创建新的路径

因此在放入字符‘c’、‘k’的时候,都创建新的路径


在放入第三个字符串的时候,头节点存在a的路径,沿着a的路径向下走

在a之后的节点,存在b的路径,沿着b的路径向下走

在b之后的节点,不存在d的节点,创建新的路径

... ...

前缀树的实现解析

前缀树的节点

这里使用的是经典的用数组表示路径,因为在前缀树的相关题目中,一般会限制字符串的范围

比如这道题目限制了字符串的范围仅在小写字母的范围之中

但当字符串的返回过大,创建数组十分浪费空间

此时可以用哈希表、有序表等表示路径

key表示当前是哪一条路,value表示下一个node节点

package trietree;public class TrieNode {int pass;//记录这个节点被经过多少次int end;//记录这个节点是多少个字符串的结尾public TrieNode[] nexts;//每个节点的之后的路径public TrieNode() {pass = 0;end = 0;nexts = new TrieNode[26];//先预设每个节点后面有26条路径//我们先设定字符串的范围仅在26个小写字母之内//a对应0、b对应1、c对应2 .....//nexts[0] == null;  表示没有a的路径//nexts[0] != null;  表示有a的路径}}

insert()方法

如何生成前缀树

pass和end在节点上,记录字符串的记录情况

经过一个节点,就给当前节点的pass++

当字符串遍历完成,给最后一个节点的end++ 

根节点的pass表示加入了多少个字符串

根节点的end表示加入了多少个空字符串

如果加入一个空字符串,那么根节点的pass+1,end+1

insert部分代码

package trietree;public class TrieTree {private TrieNode root;public TrieTree(){root = new TrieNode();}public void insert(String str) {if (str == null) {//加入空字符串时,头节点的pass++、end++root.pass++;root.end++;return;}char[] chs = str.toCharArray();//把字符串切分为char型数组TrieNode node = root;node.pass++;int index = 0;for (int i = 0; i < chs.length; i++) {index = chs[i] - 'a';//a对应0、b对应1、c对应2 ...if (node.nexts[index] == null) {//不存在对应的路径node.nexts[index] = new TrieNode();//创建一个路径 == 为nexts数组赋值 == 创建下一个新的节点}//如果存在对应的路径,复用节点,下一个节点的pass++node = node.nexts[index];//node向下node.pass++;//此时是下一个节点,下一个节点的pass++}node.end++;//遍历完成一个字符串之后,end++}
}

search()方法

查询一个字符串str加入过几次

沿着字符串str从头节点向下查找

查找到str的最后一个字符的时候,当时的node节点的end值就是str加入的次数

如果查到一半其中一个节点没有后续节点,那么说明没有加入过,直接返回0

    //查询一个字符串str加入过几次public int search(String str) {TrieNode node = root;//头节点char[] chs = str.toCharArray();int index = 0;for (int i = 0; i < chs.length; i++) {index = chs[i] - 'a';if (node.nexts[index] == null) {//如果查到一半其中一个节点没有后续节点,那么说明没有加入过,直接返回0return 0;}node = node.nexts[index];//node向下查找}return node.end;//查找到str的最后一个字符的时候,当时的node节点的end值就是str加入的次数}

prefixNumber()方法 

查询所有加入的字符串中,有几个是以pre为前缀的

沿着字符串pre从头节点向下查找

查找到pre的最后一个字符的时候,当时的node节点的pass值就是str加入的次数

如果查到一半其中一个节点没有后续节点,那么说明没有以pre为前缀的,直接返回0

    //查询所有加入的字符串中,有几个是以pre为前缀的public int prefixNumber(String pre) {TrieNode node = root;//头节点char[] chs = pre.toCharArray();int index = 0;for (int i = 0; i < chs.length; i++) {index = chs[i] - 'a';if (node.nexts[index] == null) {//如果查到一半其中一个节点没有后续节点,那么说明没有以pre为前缀的,直接返回0return 0;}node = node.nexts[index];//node向下查找}return node.end;//查找到pre的最后一个字符的时候,当时的node节点的pass值就是str加入的次数}

delete()方法

删除在前缀树中的字符串(怎么加的怎么删)

经过一个节点,就给当前节点的pass--

当字符串遍历完成,给最后一个节点的end--

注意当节点的pass值为0的时候,这个节点不存在,把整个节点及其后续节点全部标空

    public void delete(String str) {if(search(str) == 0){//先确认前缀树中是否加入过str,如果没有加入过,直接返回return;}if (str == null) {//删除空字符串时,头节点的pass--、end--root.pass--;root.end--;return;}char[] chs = str.toCharArray();TrieNode node = root;node.pass--;int index = 0;for (int i = 0; i < chs.length; i++) {index = chs[i] - 'a';//当节点的pass值为0的时候,这个节点不存在,把整个节点及其后续节点全部标空if (node.pass == 0) {node = null;//Java的JVM在标空为null之后,会自动释放内存return;}node = node.nexts[index];//node向下node.pass--;//下一个节点的pass--}node.end--;//遍历完成一个字符串之后,end--}

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

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

相关文章

HTML5+ API 爬坑记录

背景: 有个比较早些使用5开发的项目, 最近两天反馈了一些问题, 解决过程在此记录; 坑1: plus.gallery.pick 选择图片没有进入回调 HTML5 API Reference 在 联想小新 平板电脑上选择相册图片进行上传时, 打开相册瞬间 应用会自动重启, 相册倒是有打开, 不过应用重启了, 导…

开启数据库审计(db,extended级别或os级别),并将审计文件存放到/home/oracle/audit下

文章目录 开启数据库审计&#xff08;db,extended级别或os级别&#xff09;&#xff0c;并将审计文件存放到/home/oracle/audit下一. 简介二. 配置2.1. 审计是否安装2.2. 审计表空间迁移2.3. 审计参数2.4. 审计级别2.5. 其他审计选项2.6. 审计相关视图 三. 使用3.1. 开启/关闭审…

Nginx反向代理实现负载均衡+Keepalive实现高可用

目录 实现负载均衡 实现高可用 实现负载均衡 Nginx的几种负载均衡算法&#xff1a; 1.轮询&#xff08;默认&#xff09; 每个请求按照时间顺序逐一分配到下游的服务节点&#xff0c;如果其中某一节点故障&#xff0c;nginx 会自动剔除故障系统使用户使用不受影响。 2.权重…

JDK11新特性

目录 一、JShell 二、Dynamic Class-File Constants类文件新添的一种结构 三、局部变量类型推断&#xff08;var ”关键字”&#xff09; 四、新加的一些实用API 1. 新的本机不可修改集合API 2. Stream 加强 3. String 加强 4. Optional 加强 5. 改进的文件API 五、移…

【解决】HDFS JournalNode启动慢问题排查

文章目录 一. 问题描述二. 问题分析1. 排查机器性能2. DNS的问题 三. 问题解决 一句话&#xff1a;因为dns的问题导致journalnode启动时很慢&#xff0c;通过修复dns对0.0.0.0域名解析&#xff0c;修复此问题。 一. 问题描述 从journalnode启动到服务可用&#xff0c;完成RPC…

Android : ExpandableListView(折叠列表) +BaseExpandableListAdapter-简单应用

示例图&#xff1a; 实体类DemoData.java package com.example.myexpandablelistview.entity;public class DemoData {private String content;private int img;public DemoData(String content, int img) {this.content content;this.img img;}public String getContent()…

VL06O报表添加增强字段

业务描述 用户需要在VL06O事务代码下进行批量交货过账&#xff0c;现有的筛选条件不太适用当前公司的业务&#xff0c;需要在报表中新增三个交货单增强字段&#xff0c;方便其筛选&#xff08;选择屏幕没有加&#xff0c;用户在报表里用标准按钮功能自己筛选&#xff09; 效果…

Redis集群环境各节点无法互相发现与Hash槽分配异常 CLUSTERDOWN Hash slot not served的解决方式

原创/朱季谦 在搭建Redis5.x版本的集群环境曾出现各节点无法互相发现与Hash槽分配异常 CLUSTERDOWN Hash slot not served的情况&#xff0c;故而把解决方式记录下来。 在以下三台虚拟机机器搭建Redis集群—— 192.168.200.160192.168.200.161192.168.200.162启动三台Redis集…

python连接并简单操作SQL server数据库

环境&#xff1a; pycharm 、SQLserver版本2019 1.首先&#xff0c;在pycharm中点击File&#xff0c;找到setting——project&#xff1a;***&#xff0c;点击”“&#xff0c;引入pymssql库 2.编写代码连接数据库&#xff0c;并对数据库进行查询等简单操作&#xff08;此处仅…

C#,数值计算——多项式插值与外推插值(Poly2D_interp)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Object for two-dimensional polynomial interpolation on a matrix.Construct /// with a vector of x1 values, a vector of x2 values, a matrix of tabulated /// func…

代码随想录算法训练营第五十二天|1143.最长公共子序列 1035.不相交的线 53. 最大子序和

文档讲解&#xff1a;代码随想录 视频讲解&#xff1a;代码随想录B站账号 状态&#xff1a;看了视频题解和文章解析后做出来了 1143.最长公共子序列 class Solution:def longestCommonSubsequence(self, text1: str, text2: str) -> int:dp [[0] * (len(text2) 1) for _ i…

LeetCode | 622. 设计循环队列

LeetCode | 622. 设计循环队列 OJ链接 思路&#xff1a; 我们这里有一个思路&#xff1a; 插入数据&#xff0c;bank往后走 删除数据&#xff0c;front往前走 再插入数据&#xff0c;就循环了 那上面这个方法可行吗&#xff1f; 怎么判断满&#xff0c;怎么判断空&#xff1…