返回顶部
首页 > 资讯 > 后端开发 > Python >详解Java中字典树(Trie树)的图解与实现
  • 930
分享到

详解Java中字典树(Trie树)的图解与实现

2024-04-02 19:04:59 930人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录简介工作过程数据结构初始化构建字典树应用匹配有效单词关键词提示总结简介 Trie又称为前缀树或字典树,是一种有序树,它是一种专门用来处理串匹配的数据结构,用来解决一组字符中快速查

简介

Trie又称为前缀树或字典树,是一种有序树,它是一种专门用来处理串匹配的数据结构,用来解决一组字符中快速查找某个字符串的问题。Google搜索的关键字提示功能相信大家都不陌生,我们在输入框中进行搜索的时候,会下拉出一系列候选关键词。

image-20220511111955847

上面这个关键词提示功能,底层最基本的原理就是我们今天说的数据结构:Trie树

我们先看看Tire树长什么样子,以单纯的单词匹配为例,首先它是一棵多叉树结构,根节点是一个空字符,树中节点分为普通节点和结尾节点(如图中红色节点)。结尾节点表示加上前面前缀,可以称为一个单词,如图中hi,him。

image-20220511113614538

工作过程

Tire树与之前串匹配最大的不同点是,之前我们都是单模式串,查看主串中是否有与模式串匹配的子串,操作过程也是用模式串去与主串进行比较。而Tire树是多模式串,我们先将模式串提前构建成Tire树,然后查看主串是否匹配模式串,且更适用于类似如上关键词提示的前缀匹配。接下来我们自己通过实现一个简易的关键词提示功能来讲解Tire树。

数据结构

一个value存储当前节点值,用一个26大小的数组存储当前节点的孩子节点,这是一个简单但是可能产生浪费的方法,可以采用有序存入采用二分法查找,或者采用hash表,跳表进行优化。一个标志当前节点是否可作为尾节点


    public static class node{
        //当前节点值
        private char value;
        //当前节点的孩子节点
        private Node[] childNode;
        //标志当前节点是否是某单词结尾
        private boolean isTail;
        public Node(char value) {
            this.value = value;
        }
    }

初始化

初始化一个仅有root节点的Tire树,root节点值为'/0'。

Node root;
public void init() {
        root = new Node('\0');
        root.childNode = new Node[26];
}

构建字典树

将需要加入的模式串加入Tire树,遍历当前字符串字符,从Tire树根节点开始查找当前字符,如果字符已经存在不需要处理,并且从这个字符节点出发,查看下一个字符是否存在,如果当前节点不存Tire树,才需要插入当前字符,当插入最后一个字符时需要标志当前字符节点为尾节点。

image-20220511222429713


    public void insertStr(char[] chars) {
        //首先判断首字符是否已经在字典树中,然后判断第二字符,依次往下进行判断,找到第一个不存在的字符进行插入孩节点
        Node p = root;
        //表明当前处理到了第几个字符
        int chIndex = 0;
        while (chIndex < chars.length) {
            while (chIndex < chars.length && null != p) {
                Node[] children = p.childNode;
                boolean find = false;
                for (Node child : children) {
                    if (null == child) {continue;}
                    if (child.value == chars[chIndex]) {
                        //当前字符已经存在,不需要再进行存储
                        //从当前节点出发,存储下一个字符
                        p = child;
                        ++ chIndex;
                        find = true;
                        break;
                    }
                }
                if (Boolean.TRUE.equals(find)) {
                    //在孩子中找到了 不用再次存储
                    break;
                }
                //如果把孩子节点都找遍了,还没有找到这个字符,直接将这个字符加入当前节点的孩子节点
                Node node = new Node(chars[chIndex]);
                node.childNode = new Node[26];
                children[chars[chIndex] - 'a'] = node;
                p = node;
                ++ chIndex;
            }
        }
        //字符串中字符全部进入tire树中后,将最后一个字符所在节点标志为结尾节点
        p.isTail = true;
    }

应用

匹配有效单词

遍历字符串,从根节点出发,查看字符是否存在,只要存在不存在的情况,直接返回false,如果每个字符都存在,判断最后一个字符是否为结尾节点,如果不是,到这里还不是一个有效单词,返回false,否则,返回true。

 
    public boolean isMatch(String str) {
        //从root开始进行匹配,只要有一个找不到即为匹配失败
        char[] chars = str.toCharArray();
        int chIndex = 0;
        Node p = root;
        while (null != p) {
            Node[] children = p.childNode;
            boolean flag = false;
            for (Node child : children) {
                if (null == child) {continue;}
                if (child.value == chars[chIndex]) {
                    flag = true;
                    p = child;
                    ++ chIndex;
                    //当比较最后一个字符的时候,这个字符需要是结尾字符才能完全匹配
                    if (chIndex == chars.length && p.isTail) {
                        return true;
                    }
                    break;
                }
            }
            if (Boolean.FALSE.equals(flag)) {
                return false;
            }
        }
        return false;
    }

测试样例

public static void main(String[] args) {
        //he, him, lot, a
        //初始化Tire树
        Trie trie = new Trie();
        trie.init();
        //构建Tire树,只有以下单词才是有效单词
        trie.insertStr("he".toCharArray());
        trie.insertStr("him".toCharArray());
        trie.insertStr("lot".toCharArray());
        trie.insertStr("a".toCharArray());
        //匹配字符串是否为有效单词
        System.out.println(trie.isMatch("lot"));
        System.out.println(trie.isMatch("lit"));

    }

运行结果

image-20220511223308571

关键词提示

根据输入的关键词前缀,匹配所有可能出现的关键词。首先遍历字符串,从节点出发,只要有一个找不到,直接返回null,直至找到最后一个字符对应的节点,从该节点出发找到所有尾节点。

 
    public List<String> findStrPrefix(String str) {
        //根据str首先找到str最后一个字符,然后从这个字符出发,找到所有字符串
        List<String> result = new ArrayList<>();
        char[] chars = str.toCharArray();
        //分成两步走
        //1。找到str最后一个自字符在字典树中的node
        //2。从该node出发,找到所有的结尾node,即为以str为前缀的字符串
        int chIndex = 0;
        Node p = root;
        while (null != p && chIndex < chars.length) {
            Node[] children = p.childNode;
            boolean flag = false;
            for (Node child : children) {
                if (null == child) {continue;}
                if (child.value == chars[chIndex]) {
                    //已经找到
                    p = child;
                    flag = true;
                    ++ chIndex;
                    break;
                }
            }
            //如果没有找到,直接返回空
            if (Boolean.FALSE.equals(flag)) {
                return null;
            }
        }
        //找到了最后一个节点
        //深度优先遍历,查找所有尾节点
        this.dfs(p, new StringBuilder(str), result);
        return result;
    }

    public void dfs(Node p, StringBuilder str, List<String> result) {
        Node[] children = p.childNode;
        for (Node child : children) {
            if (null == child) {
                continue;
            }
            str.append(child.value);
            if (child.isTail) {
                result.add(str.toString());
            }
            //再递归查当前节点的孩子节点
            dfs(child, str, result);
            //需要将刚刚set进去的节点删除,否则影响当前节点的下一个孩子节点
            //举个例子,h的孩子节点有e,i,当e放进去之后不拿出来,在遍历到i的时候,就会形成hei
            str.setLength(str.length() - 1);
        }
    }

测试样例

public static void main(String[] args) {
        //he, him, lot, a
        //初始化Tire树
        Trie trie = new Trie();
        trie.init();
        //构建Tire树,只有以下单词才是有效单词
        trie.insertStr("he".toCharArray());
        trie.insertStr("him".toCharArray());
        trie.insertStr("lot".toCharArray());
        trie.insertStr("a".toCharArray());
        //匹配字符串是否为有效单词
        List<String> strings = trie.findStrPrefix("h");
    }

运行结果

总结

到这里Trie树就讲完了,主要就是聚合前缀,通过树的特性,按照链路进行访问,同时标志尾节点,标志到当前节点是一个完整的字符串。

以上就是详解Java中字典树(Trie树)的图解与实现的详细内容,更多关于Java字典树的资料请关注编程网其它相关文章!

--结束END--

本文标题: 详解Java中字典树(Trie树)的图解与实现

本文链接: https://lsjlt.com/news/148604.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 详解Java中字典树(Trie树)的图解与实现
    目录简介工作过程数据结构初始化构建字典树应用匹配有效单词关键词提示总结简介 Trie又称为前缀树或字典树,是一种有序树,它是一种专门用来处理串匹配的数据结构,用来解决一组字符中快速查...
    99+
    2024-04-02
  • 详解字典树Trie结构及其Python代码实现
    字典树(Trie)可以保存一些字符串->值的对应关系。基本上,它跟 Java 的 HashMap 功能相同,都是 key-value 映射,只不过 Trie 的 key 只能是字符串。 Trie 的强...
    99+
    2022-06-04
    字典 详解 结构
  • Java中关于字典树的算法实现
    字典树(前缀树)算法实现 前言 字典树,又称单词查找树,是一个典型的 一对多的字符串匹配算法。“一”指的是一个模式串,“多”指的是多个模板串。字典树经常被用来统计、排序和保存大量的字...
    99+
    2024-04-02
  • Java中怎么实现一个双数组Trie树
    本篇文章给大家分享的是有关Java中怎么实现一个双数组Trie树,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。对于插入字符串,如果有一个字符串是另一个字符串的子串的话,我是将结...
    99+
    2023-06-17
  • Java实现前缀树详解
    目录一.前缀树1.什么是前缀树2.前缀树的举例二.前缀树的实现1.前缀树的数据结构2.插入字符串3.查找字符串4.查找前缀三.词典中最长的单词1.题目描述2.问题分析3.代码实现一....
    99+
    2023-05-18
    Java前缀树 Java前缀树实现
  • python字典生成树状图的实例
    目录python字典生成树状图python生成树结构python字典生成树状图 from graphviz import Digraph # 获取所有节点中最多子节点的叶节点 de...
    99+
    2024-04-02
  • 详解Java中的树结构
    这篇文章将为大家详细讲解有关详解Java中的树结构,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。常用的java框架有哪些1.SpringMVC,Spring Web MVC是一种基于Java...
    99+
    2023-06-14
  • 关于Java的二叉树、红黑树、B+树详解
    目录1、二叉查找树2、平衡二叉查找树3、红黑树:4、 B树:5、 B+树6、红黑树 VS B+树数组和链表是常用的数据结构,数组虽然查找快(有序数组可以通过二分法查找),但是插入和删...
    99+
    2023-05-20
    Java二叉树 Java红黑树 JavaB+树
  • Python实现简单字典树的方法
    本文实例讲述了Python实现简单字典树的方法。分享给大家供大家参考,具体如下: #coding=utf8 """代码实现了最简单的字典树,只支持由小写字母组成的字符串。 在此代码基础上扩展一下,就可以...
    99+
    2022-06-04
    字典 简单 方法
  • 详解Java 二叉树的实现和遍历
    目录什么是二叉树二叉树建树前序建树中序建树后序建树二叉树的遍历什么是二叉树 简单理解为对于一个节点来说,最多拥有一个上级节点,同时最多具备左右两个下级节点的数据结构。 由于很多排序算...
    99+
    2024-04-02
  • 详解B树删除操作:使用Python实现B树删除操作的详细图解
    B树删除操作需要考虑节点所在位置和平衡,并且很有可能会发生下溢的情况。当一个节点包含的子节点数量少于它应该持有的最小数量时,就会发生下溢。 图文展示B树删除操作原理 在不影响平衡情况下。 下溢情况。 删除内部节点。 Python实...
    99+
    2024-01-22
    B树的概念
  • Java递归实现菜单树的方法详解
    pom文件 <xml version="1.0" encoding="UTF-8"> <project xmlns="http://maven.apache.or...
    99+
    2024-04-02
  • Java实现二叉树的基本操作详解
    目录1. 二叉树结点的构成2. 二叉树的遍历2.1 前序遍历2.2 中序遍历2.3 后序遍历3. 获取整棵二叉树的节点个数4. 获取二叉树叶子节点的个数5. 获取第K层节点的个数6....
    99+
    2022-11-13
    Java二叉树操作 Java二叉树
  • Java详解AVL树的应用
    目录一.什么是AVL树1.二叉搜索树2.为什么引入了AVL树3.什么是AVL树二.自己构造AVL树三.AVL树的插入和删除1.插入1.1.右单旋1.2.左单旋1.3.左右双旋1.4....
    99+
    2024-04-02
  • Java实现最小生成树算法详解
    目录定义带权图的实现Kruskal 算法二叉堆并查集实现算法Prim 算法定义 在一幅无向图G=(V,E) 中,(u,v) 为连接顶点u和顶点v的边,w(u,v)...
    99+
    2024-04-02
  • C++实现AVL树的示例详解
    目录AVL 树的概念AVL 树的实现节点的定义接口总览插入旋转AVL 树的概念 也许因为插入的值不够随机,也许因为经过某些插入或删除操作,二叉搜索树可能会失去平衡,甚至可能退化为单链...
    99+
    2023-03-03
    C++实现AVL树 C++ AVL树
  • C++ 线段树原理与实现示例详解
    目录一、问题引入二、线段树的构建三、线段树的单点修改与查询1、修改2、查询四、线段树的区间修改与查询1、修改2、查询一、问题引入 对于一般的区间问题,比如RMQ(区间的最值)、区间的...
    99+
    2024-04-02
  • Python实现二叉树结构与进行二叉树遍历的方法详解
    二叉树的建立 使用类的形式定义二叉树,可读性更好 class BinaryTree: def __init__(self, root): self.key = root sel...
    99+
    2022-06-04
    二叉树 遍历 详解
  • Java实现二叉查找树的增删查详解
    目录定义增加节点查询节点删除节点定义 二叉查找树(ADT)是一个具有对于树种的某个节点X,它的左节点都比X小,它的右节点都比X大的二叉树。如下就是一个符合 要求的二叉查找树: 增加...
    99+
    2024-04-02
  • java基础二叉搜索树图文详解
    目录概念直接实践准备工作:定义一个树节点的类,和二叉搜索树的类。搜索二叉树的查找功能搜索二叉树的插入操作搜索二叉树 删除节点的操作 - 难点性能分析总程序 - 模拟实现二叉搜索树和 ...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作