前缀树及其实现解析

前缀树

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

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

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

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

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) {//如果查到一半其中一个节点没有后续节点,那么说明没有加入过,直接返回0
                return 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为前缀的,直接返回0
                return 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--
    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

P8599 [蓝桥杯 2013 省 B] 带分数(dfs+全排列+断点判断)

思路&#xff1a;1.深度枚举所有排列情况 2.设置为每个排列设置两个断点&#xff0c;分为三部分&#xff1a;a,b,c 3.转换为乘法判断条件&#xff0c;满足加一 代码如下&#xff1a;&#xff08;可用next_permutation全排列函数代替dfs&#xff09; #include<iostream>…

2016年全国硕士研究生入学统一考试管理类专业学位联考数学试题——解析版

文章目录 2016 级考研管理类联考数学真题一、问题求解&#xff08;本大题共 15 小题&#xff0c;每小题 3 分&#xff0c;共 45 分&#xff09;下列每题给出 5 个选项中&#xff0c;只有一个是符合要求的&#xff0c;请在答题卡上将所选择的字母涂黑。真题&#xff08;2016-01&…

Python接口自动化测试——如何搭建测试环境

前言 接口测试的方式有很多&#xff0c;比如可以用工具&#xff08;jmeter,postman&#xff09;之类&#xff0c;也可以自己写代码进行接口测试&#xff0c;工具的使用相对来说都比较简单&#xff0c;重点是要搞清楚项目接口的协议是什么&#xff0c;然后有针对性的进行选择&a…

Android——资源IDnonFinalResIds和“Attribute value must be constant”错误

一、异常描述 通过资源ID引用资源提示错误 Attribute value must be constant 二、解决方案 在根目录下的文件 gradle.properties 中添加如下配置&#xff0c;然后Sync Project android.nonFinalResIdsfalse 三、问题原因 android.nonFinalResIds 是Android开发中一个用于解…

STM32 MAP文件

文章目录 1 生成Map2 map中概念3 文件分析流程3.1 Section Cross References3.2 Removing Unused input sections from the image&#xff08;移除未使用的段&#xff09;3.3 Memory Map of the image&#xff08;映像的内存分布&#xff09;3.3.1 加载域3.3.2 运行域 4 代码运…

记录一次因内存不足而导致hiveserver2和namenode进程宕机的排查

背景 最近发现集群主节点总有进程宕机&#xff0c;定位了大半天才找到原因&#xff0c;分享一下 排查过程 查询hiveserver2和namenode日志&#xff0c;都是正常的&#xff0c;突然日志就不记录了&#xff0c;直到我重启之后又恢复工作了。 排查各种日志都是正常的&#xff0…

Doris 建表示例(七)

建表语法 使用 CREATE TABLE 命令建立一个表(Table)。更多详细参数可以查看&#xff1a; HELP CREATE TABLE; 建表语法&#xff1a; CREATE [EXTERNAL] TABLE [IF NOT EXISTS] [database.]table_name(column_definition1[, column_definition2, ...][, index_definition1[, i…

ELK架构

经典的ELK 经典的ELK主要是由Filebeat Logstash Elasticsearch Kibana组成&#xff0c;如下图&#xff1a;&#xff08;早期的ELK只有Logstash Elasticsearch Kibana&#xff09; 此架构主要适用于数据量小的开发环境&#xff0c;存在数据丢失的危险。 整合消息队列Ngin…

【Spring Cloud实战】分布式系统控制与组件应用

在现代软件开发中&#xff0c;分布式系统已经成为一种常见的架构模式&#xff0c;被广泛应用于各种规模的企业和组织中。这种架构模式通过将应用程序拆分为独立的组件&#xff0c;并分布在不同的计算机节点上运行&#xff0c;使得系统能够应对高负载和大规模的数据处理需求&…

视频剪辑达人分享:高效减片头时长并调整播放速度的技巧,提升视频品质

在视频剪辑的过程中&#xff0c;许多初学者经常会遇到一些问题&#xff0c;如片头过长、播放速度不适当等&#xff0c;这些问题不仅会影响观众的观看体验&#xff0c;还会对视频品质产生负面影响。在调整播放速度时&#xff0c;要根据视频内容来进行调整。一般来说&#xff0c;…

双流网络论文精读笔记

精读视频&#xff1a;双流网络论文逐段精读【论文精读】_哔哩哔哩_bilibili Two-Stream Convolutional Networks for Action Recognition in Videos 传统的神经网络难以学习到物体的运动信息&#xff0c;双流网络则通过光流将物体运动信息抽取出来再传递给神经网络 给模型提供…

Qt 软件开发框架(主要部分)

目录 1、 一个软件基本要素 &#xff08;1&#xff09;UI模块 &#xff08;2&#xff09;网络模块 &#xff08;3&#xff09;业务逻辑模块 &#xff08;4&#xff09;中间层 &#xff08;5&#xff09;独立模块&#xff08;守护进程、更新模块、日志收集模块…&#xff…

蓝桥杯物联网竞赛_STM32L071_3_Oled显示

地位&#xff1a; 对于任何一门编程语言的学习&#xff0c;print函数毫无疑问是一种最好的调试手段&#xff0c;调试者不仅能通过它获取程序变量的运行状态而且通过对其合理使用获取程序的运行流程&#xff0c;更能通过关键变量的输出帮你验证推理的正确与否&#xff0c;朴素的…

Rust开发——数据对象的内存布局

枚举与Sized 数据 一般数据类型的布局是其大小&#xff08;size&#xff09;、对齐方式&#xff08;align&#xff09;及其字段的相对偏移量。 1. 枚举&#xff08;Enum&#xff09;的布局&#xff1a; 枚举类型在内存中的布局通常是由编译器来确定的。不同的编译器可能有不…

如何使用springboot服务端接口公网远程调试——实现HTTP服务监听

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构、算法模板 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 二. 内网穿透…

Java面试-微服务篇-SpringCloud

Java面试-微服务篇-SpringCloud SpringCloud 常见组件注册中心Eureka, Nacos负载均衡Ribbon服务雪崩, 熔断降级微服务的监控来源 SpringCloud 常见组件 通常情况下 Eureka: 注册中心Ribbon: 负载均衡Feign: 远程调用Hystrix: 服务熔断Zuul/Gateway: 网关 SpringCloudAlibaba…

C++程序中dump文件生成方法详解

最近项目中新作成了一个动态链接库&#xff0c;长时间运行后&#xff0c;偶尔会崩溃。根据log分析&#xff0c;被调用的动态库函数最外层catch到了这个异常&#xff0c;但是不能定位哪里出了问题。另外虽然上层exe是有dump文件输出处理的&#xff0c;但是在C中&#xff0c;如果…

Python requests请求响应以流stream的方式打印输出

如果你使用的请求库是requests&#xff0c;那么你必须了解的大模型里的请求怎么响应式的接收并打印出来的。 这里给大家写一下正式的书写方式: import requestsurl "http://localhost:8080/stream"payload {} headers {}response requests.request("GET&q…

创新洞察|展望2030 – 企业数字化转型的10大趋势(阿里研究院)

企业是否一定要 数字化创新 转型&#xff1f;究竟如何数字化转型&#xff1f;难点和坑又是什么&#xff1f;阿里研究院副院长针对未来十年中国的数字化转型提出十个方面需要关注的趋势&#xff1a;1.大国优势 2. 重构的消费者决策体系 3. 下一代数字原生企业 4. 所有企业都会成…

Endnote软件添加期刊引用格式

在下述网址中&#xff0c;找到你想要添加的期刊&#xff0c;下载引用格式文件&#xff08;后缀为.ens格式&#xff09; https://endnote.com/downloads/styles/?wpv_post_searchInformationfusion&wpv_aux_current_post_id12829&wpv_view_count12764-TCPID12829 下载…