Trie 字典树的两种实现方式

        Trie,又称字典树、单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

上图是一棵Trie树,表示了关键字集合{“a”, “to”, “tea”, “ted”, “ten”, “i”, “in”, “inn”} 。从上图可以归纳出Trie树的基本性质:

  • 根节点不包含字符,除根节点外的每一个子节点都包含一个字符。
  • 从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。
  • 每个节点的所有子节点包含的字符互不相同。
  • 从第一字符开始有连续重复的字符只占用一个节点,比如上面的to,和ten,中重复的单词t只占用了一个节点。

字典树的实现有递归与非递归的两种方式:

非递归:

非递归的实现也有两种方式,一种是利用自己创建的节点来实现,具体实现如下:

public class Trie {
    public static void main(String[] args) {
        Trie trie = new Trie();
        trie.add("apple");
        System.out.println(trie.contains("apple"));
        System.out.println(trie.isPrefix("app"));
    }
    private class TreeNode{
        public boolean isWord;
        public TreeMap<Character,TreeNode> next;
        public TreeNode(){
            this(false);
            next = new TreeMap<>();
        }
        public TreeNode(boolean isWord){
            this.isWord = isWord;
        }
    }
    private TreeNode root;
    private int size;
    public Trie(){
        this.root = new TreeNode();
        this.size = 0;
    }
    public int getSize(){
        return size;
    }
    public void add(String str){
        TreeNode cur = root;
        for(int i=0;i<str.length();i++){
            char c = str.charAt(i);
            if(cur.next.get(c) == null){
                //新建节点
                cur.next.put(c, new TreeNode());
            }
            //否则,就直接走到该节点位置即可
            cur = cur.next.get(c);
        }
        if(!cur.isWord){
            //确定cur是新的单词
            cur.isWord = true;
            size++;
        }
    }
    public boolean contains(String str){
        TreeNode cur = root;
        for(int i=0;i<str.length();i++){
            char c = str.charAt(i);
            if(cur.next.get(c) == null) return false;
            cur = cur.next.get(c);
        }
        return cur.isWord;
    }
    public boolean isPrefix(String prefix){
        TreeNode cur = root;
        for(int i=0;i<prefix.length();i++){
            char c = prefix.charAt(i);
            if(cur.next.get(c) == null) return false;
            cur = cur.next.get(c);
        }
        return true;
    }

}

这种实现方式是利用自己创建的节点实现的。每一个Trie对象内部都存在一个TreeNode对象与size对象。其中TreeNode对象内部存在着一个TreeMap,TreeMap内存储着每一个字符与下一个节点的对应关系。

当然,也有另一种实现方式:

class Trie {
    private Trie[] children;
    private boolean isWord;
    public Trie() {
        children = new Trie[26];
        isWord = false;
    }
    
    public void insert(String word) {
        Trie node = this;
        for(char c : word.toCharArray()){
            int idx = c - 'a';
            if(node.children[idx] == null){
                node.children[idx] = new Trie();
            }
            node = node.children[idx];
        }
        node.isWord = true;
    }
    
    public boolean search(String word) {
        Trie node = searchPrefix(word);
        return node != null && node.isWord;
    }
    
    public boolean startsWith(String prefix) {
        return searchPrefix(prefix) != null;
    }
    public Trie searchPrefix(String word){
        Trie node = this;
        for(char c : word.toCharArray()){
            int idx = c - 'a';
            if(node.children[idx] != null){
                node = node.children[idx];
            }else{
                return null;
            }
        }
        return node;
    }
}

/**
 * Your Trie object will be instantiated and called as such:
 * Trie obj = new Trie();
 * obj.insert(word);
 * boolean param_2 = obj.search(word);
 * boolean param_3 = obj.startsWith(prefix);
 */

这个实现方式是每一个Trie对象内部存储自己的Trie[]数组,由此实现节点的对应关系。

递归
public void recursionAdd(String word) {
    Node cur = root;
    add(root, word, 0);
}

/**
  * 递归写法调用方法实现递归添加
  *
  * @param node 传入要进行添加的节点
  * @param word 传入要进行添加的单词
  */
public void add(Node node, String word, int index) {
    // 确定终止条件,这个终止条件在没加index这个参数时,很难确定
    // 此时一个单词已经遍历完成了,如果这个结束节点没有标记为单词,就标记为单词
    if (!node.isWord && index == word.length()) {
        node.isWord = true;
        size++;
    }

    if (word.length() > index) {
        char addLetter = word.charAt(index);
        // 判断trie的下个节点组中是否有查询的字符,如果没有,就添加
        if (node.next.get(addLetter) == null) {
            node.next.put(addLetter, new Node());
        }
        // 基于已经存在的字符进行下个字符的递归查询
        add(node.next.get(addLetter), word, index + 1);
    }
}

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

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

相关文章

github Two-factor authentication (2FA)is required for your GitHub account

问题 github 2FA认证 详细问题 笔者使用GitKraken&#xff0c;使用github登录&#xff0c;github要去 Two-factor authentication (2FA)is required for your GitHub account&#xff0c;即进行2FA认证 解决方案 解决方案一、 微信 → \rightarrow →搜索腾讯身份验证器…

内存块与内存池

&#xff08;1&#xff09;在运行过程中&#xff0c;MemoryPool内存池可能会有多个用来满足内存申请请求的内存块&#xff0c;这些内存块是从进程堆中开辟的一个较大的连续内存区域&#xff0c;它由一个MemoryBlock结构体和多个可供分配的内存单元组成&#xff0c;所有内存块组…

java 培训班预定管理系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目

一、源码特点 java 培训班预定管理系统是一套完善的java web信息管理系统 采用serlvetdaobean&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xf…

java 宠物医院系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 java 宠物医院系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

Excel如何把窗口冻结,在下拉滚动条的时候仍然可以看到前几行数据?

** 共分2个情况&#xff1a; ①&#xff1a; 冻结首行&#xff1a; 作用&#xff1a;只冻结第一行的数据窗口。在下拉滚动条时&#xff0c;首行不会动&#xff0c;其他数据行会动步骤如下&#xff1a;1、鼠标放在首行的最左边&#xff0c;然后左键点一下先选中整行2、然后&am…

OpenAI发布Sora技术报告深度解读!真的太强了!

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号&#xff1a;洲与AI。 &#x1f388; 本文专栏&#xff1a;本文收录…

IP地址+子网掩码+CIDR学习笔记

目录 一、IP地址 1、表示方法&#xff1a; 2、特殊IP地址 二、子网掩码 1、判断网络位和主机位 2、子网划分 三、无分类编址CIDR 1、CIDR路由汇聚 汇聚规则&#xff1a; 汇聚ID&#xff1a; 2、最佳路由匹配原则 一、IP地址 1、表示方法&#xff1a; 机器中存放的…

UE Get节点和源码

文章目录 概要UE Get节点有哪些常见的应用场景相关源码 概要 UE Get节点在Unreal Engine的蓝图系统中用于获取变量的值。这个节点通常用于从变量中读取数据&#xff0c;以便在游戏的逻辑流程中使用。 要使用Get节点&#xff0c;你首先需要有一个已经定义的变量。然后&#xf…

电梯控制系列之电梯结构介绍

这篇博客介绍单部10层电梯的完整控制程序框架编写过程&#xff0c;编程语言&#xff1a;SCL&#xff0c;控制器型号&#xff1a;S7-1200PLC。本篇博客介绍和电梯控制相关的一些电梯结构介绍。本文只可作为学习参考资料&#xff0c;行业控制需要遵循电梯安全相关规范。 1、电梯…

【Linux系统化学习】缓冲区

目录 缓冲区 一个样例 现象解释 缓冲区存在的位置 缓冲区 在刚开始学习C语言的时候我们就听过缓冲区这个名词&#xff0c;很是晦涩难懂&#xff1b;在Linux下进程退出时也包含缓冲区&#xff0c;因此缓冲区到底是什么&#xff1f;有什么作用&#xff1f; 让我们先从一个小…

微服务—DSL基础语法与RestClient操作

本博客为个人学习笔记&#xff0c;学习网站&#xff1a;黑马程序员SpringCloud 2021教程 目录 DSL语法 索引库操作 mapping属性 创建索引库 字段拷贝 查询、删除、修改索引库 文档操作 新增文档 查询、删除文档 修改文档 全量修改 增量修改 DSL文档语法小结 Rest…

JWT登录验证前后端设计与实现笔记

设计内容 前端 配置全局前置路由守卫axios拦截器登录页面和主页 后端 JWT的封装登录接口中间件放行mysql数据库的连接 详细设计 路由设计 配置全局前置守卫&#xff0c;如果访问的是登录页面则放行&#xff0c;不是则进入判断是否有token&#xff0c;没有则拦截回到登录…

17-k8s控制器资源-job控制

job控制器&#xff1a;就是一次性任务的pod控制器&#xff0c;pod完成作业后不会重启&#xff0c;其重启策略是&#xff1a;Never 1&#xff0c;job控制器案例描述 启动一个pod&#xff0c;执行完成一个事件&#xff0c;然后pod关闭&#xff1b; 事件&#xff1a;计算π的值&a…

[java基础揉碎]类与对象

目录 类与对象的引出: 类与对象的概述: 类与对象在内存中的布局: 属性的注意细节: 类与对象在内存中创建的过程: 类与对象的引出: 例如这样一个问题: 如果用单独变量来解决, 就会有一个问题, 不利于数据的管理, 将所有猫的信息都给拆解了: 如果用数组来解决, 则会有 1)数…

第三百五十回

文章目录 1. 概要介绍2. 获取方法2.1 获取语言2.2 获取地址 3.示例代码3. 内容总结 我们在上一章回中介绍了"给geolocator插件提交问题"相关的内容&#xff0c;本章回中将介绍如何获取系统语言.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概要介绍 我们在本…

书生浦语-模型微调

大语言模型微调 指令微调的流程 LoRA(旁路分支微调) Xtuner微调框架 微调训练 作业 微调作业需要多训练几个epoch&#xff0c;这里训练了16个epoch

141 . 环形链表

链接 https://leetcode.cn/problems/linked-list-cycle/description/?envTypestudy-plan-v2&envIdtop-interview-150 题面 思路 : 法1 &#xff1a; 用哈希表来存之前的遍历过的结点 ; 一遍遍历&#xff0c;在遍历的过程中&#xff0c;先判断是否当前结点在哈希表…

【Redis实战】有MQ为啥不用?用Redis作消息队列!?Redis作消息队列使用方法及底层原理高级进阶

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《Redis实战与进阶》 本专栏纯属为爱发电永久免费&#xff01;&a…

IDEA配置Lombok不起作用

IDEA配置Lombok不起作用 我们通常会只用lombok来简化代码。但是使用IDEA的lombok插件时&#xff0c;Lombok并不起作用。 可以按照如下操作。 FIle -> settings ->build,excecution,deployment–>compiler–>annotation processors勾选上 enable annotation proc…

ubuntu22.04安装jenkins并配置

准备 更新系统 sudo apt update sudo apt upgrade环境准备 jdk 安装 sudo apt install openjdk-11-jdk验证 java -versiongit ubuntu配置git maven ubuntu配置maven 部署 添加 Jenkins 存储库 导入Jenkins存储库的GPG密钥 wget -q -O - https://pkg.jenkins.io/de…