Java数据结构之第十五章、Trie(前缀树/单词查找树)

简介: 1.前缀树的概念:前缀树又叫字典树或单词查找树(高效的存储和查找字符串集合的数据结构)。2.3.存储形式:存储的字符串可能:全是 小写字母 或全是 大写字母 或全是 数字 或全是 0和1。它是一棵,每个代表一个,从。字典树的根节点不包含字符,每个子节点代表一个字符,从根节点到任意一个节点所经过的路径上的字符连接起来即为该节点所代表的字符串。每个节点可以存储一个或多个字符串,通常使用一个标志来标记一个节点代表的字符串是否存在。当需要在一组字符串中查找某个字符串时,可以利用字典树来实现高效的查找操作。

 

一、前缀树

1.1前缀树相关知识

1.前缀树的概念:前缀树又叫字典树或单词查找树(高效的存储和查找字符串集合的数据结构)。

2.主要应用场景:给定一个字符串集合构建一颗前缀树,然后给定一个字符串,判断前缀树中是否包含该字符串或者该字符串的前缀。

3.存储形式:存储的字符串可能:全是 小写字母 或全是 大写字母 或全是 数字 或全是 0和1

4.字典树的核心思想是:利用字符串之间的公共前缀来节省存储空间和提高查询效率。它是一棵多叉树,每个节点代表一个字符串的前缀,从根节点到叶子节点的路径组成一个字符串。字典树的根节点不包含字符,每个子节点代表一个字符,从根节点到任意一个节点所经过的路径上的字符连接起来即为该节点所代表的字符串。每个节点可以存储一个或多个字符串,通常使用一个标志来标记一个节点代表的字符串是否存在。当需要在一组字符串中查找某个字符串时,可以利用字典树来实现高效的查找操作。

1.2前缀树的举例

    • 根结点不保存字符
    • 前缀树是一颗多叉树
    • 前缀树的每个节点保存一个字符
    • 具有相同前缀的字符串保存在同一条路径上
    • 字符串的尾处相应的在前缀树上也有结束的标志

    image.gif编辑


    二、前缀树的实现

    2.1数组实现前缀树

    2.1.1插入字符串

    private static final int[][] son=new int[100000][26];//26个字母,一共100000个数据
        private static final int[] count=new int[100000];//存储以当前这个点结尾的单词有多少个
        private int index=0;//下标为0的点,既是根节点,又是空节点
        public void insert(char[] str){
            int parent=0;
            for(int i=0;i<str.length;i++){
                int cur=str[i]-'a';
                if(son[parent][cur]==0){
                    son[parent][cur]=++index;
                }
                parent=son[parent][cur];
            }
            count[parent]++;
        }

    image.gif

    2.1.2查找字符串

    private static final int[][] son=new int[100000][26];//26个字母,一共100000个数据
        private static final int[] count=new int[100000];//存储以当前这个点结尾的单词有多少个
        private int index=0;//下标为0的点,既是根节点,又是空节点
    public int query(char[] str){
            int parent=0;
            for(int i=0;i<str.length;i++){
                int cur=str[i]-'a';
                if(son[parent][cur]==0){
                    return 0;
                }
                parent=son[parent][cur];
            }
            return count[parent];
        }

    image.gif

    2.1.3代码实现

    import java.util.Scanner;
    class Trie {
        private int[][] son=new int[100010][26];//26个字母,一共100000个数据
        private int[] count=new int[100010];//存储以当前这个点结尾的单词有多少个
        private int index=0;
        public Trie() {
        }
        public void insert(String word) {
            char[] str=word.toCharArray();
            //parent表示行
            int parent=0;
            for(int i=0;i<str.length;i++){
                //cur表示列,列表示字符串的开头元素
                int cur=str[i]-'a';
                if(son[parent][cur]==0){
                    son[parent][cur]=++index;
                }
                parent=son[parent][cur];
            }
            count[parent]++;
        }
        public boolean search(String word) {
            char[] str=word.toCharArray();
            int parent=0;
            for(int i=0;i<str.length;i++){
                int cur=str[i]-'a';
                if(son[parent][cur]==0){
                    return false;
                }
                parent=son[parent][cur];
            }
            return count[parent]!=0;
        }
        public boolean startsWith(String prefix) {
            char[] str=prefix.toCharArray();
            int parent=0;
            for(int i=0;i<str.length;i++){
                int cur=str[i]-'a';
                if(son[parent][cur]==0){
                    return false;
                }
                parent=son[parent][cur];
            }
            return true;
        }
    }

    image.gif

    2.2哈希表实现前缀树

    2.2.1插入字符串

    public void insert(String word) {
                Trie trie = this;//获得根结点
                for (char c : word.toCharArray()) {
                    if (trie.next.get(c) == null) {//当前结点不存在
                        trie.next.put(c, new Trie());//创建当前结点
                    }
                    trie = trie.next.get(c);//得到字符c的结点,继续向下遍历
                }
                trie.isEnd = true;
            }

    image.gif

    2.2.2查找字符串

    public boolean search(String word) {
                Trie trie = this;//获得根结点
                for (char c : word.toCharArray()) {
                    if (trie.next.get(c) == null) {//当前结点不存在
                        return false;
                    }
                    trie = trie.next.get(c);//得到字符c的结点,继续向下遍历
                }
                return trie.isEnd;
            }

    image.gif

    2.2.3查找前缀

    public boolean startsWith(String prefix) {
                Trie trie = this;//获得根结点
                for (char c : prefix.toCharArray()) {
                    if (trie.next.get(c) == null) {//当前结点不存在
                        return false;
                    }
                    trie = trie.next.get(c);//得到字符c的结点,继续向下遍历
                }
                return true;
            }

    image.gif

    2.2.4代码实现

    public class Trie {
            Map<Character, Trie> next;
            boolean isEnd;
            public Trie() {
                this.next = new HashMap<>();
                this.isEnd = false;
            }
            public void insert(String word) {
                Trie trie = this;//获得根结点
                for (char c : word.toCharArray()) {
                    if (trie.next.get(c) == null) {//当前结点不存在
                        trie.next.put(c, new Trie());//创建当前结点
                    }
                    trie = trie.next.get(c);//得到字符c的结点,继续向下遍历
                }
                trie.isEnd = true;
            }
            public boolean search(String word) {
                Trie trie = this;//获得根结点
                for (char c : word.toCharArray()) {
                    if (trie.next.get(c) == null) {//当前结点不存在
                        return false;
                    }
                    trie = trie.next.get(c);//得到字符c的结点,继续向下遍历
                }
                return trie.isEnd;
            }
            public boolean startsWith(String prefix) {
                Trie trie = this;//获得根结点
                for (char c : prefix.toCharArray()) {
                    if (trie.next.get(c) == null) {//当前结点不存在
                        return false;
                    }
                    trie = trie.next.get(c);//得到字符c的结点,继续向下遍历
                }
                return true;
            }
        }

    image.gif

    目录
    相关文章
    |
    4月前
    |
    存储 安全 Java
    Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
    本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
    222 3
    |
    6月前
    |
    前端开发 Java
    java实现队列数据结构代码详解
    本文详细解析了Java中队列数据结构的实现,包括队列的基本概念、应用场景及代码实现。队列是一种遵循“先进先出”原则的线性结构,支持在队尾插入和队头删除操作。文章介绍了顺序队列与链式队列,并重点分析了循环队列的实现方式以解决溢出问题。通过具体代码示例(如`enqueue`入队和`dequeue`出队),展示了队列的操作逻辑,帮助读者深入理解其工作机制。
    184 1
    |
    6月前
    |
    存储 Java 编译器
    Java 中 .length 的使用方法:深入理解 Java 数据结构中的长度获取机制
    本文深入解析了 Java 中 `.length` 的使用方法及其在不同数据结构中的应用。对于数组,通过 `.length` 属性获取元素数量;字符串则使用 `.length()` 方法计算字符数;集合类如 `ArrayList` 采用 `.size()` 方法统计元素个数。此外,基本数据类型和包装类不支持长度属性。掌握这些区别,有助于开发者避免常见错误,提升代码质量。
    572 1
    |
    7月前
    |
    存储 自然语言处理 数据库
    【数据结构进阶】AVL树深度剖析 + 实现(附源码)
    在深入探讨了AVL树的原理和实现后,我们不难发现,这种数据结构不仅优雅地解决了传统二叉搜索树可能面临的性能退化问题,还通过其独特的平衡机制,确保了在任何情况下都能提供稳定且高效的查找、插入和删除操作。
    569 19
    |
    7月前
    |
    算法 Java
    算法系列之数据结构-Huffman树
    Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
    173 3
     算法系列之数据结构-Huffman树
    |
    9月前
    |
    C++
    【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
    本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
    175 10
    |
    9月前
    |
    存储 C++
    【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
    【数据结构——树】哈夫曼树(头歌实践教学平台习题)【合集】目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果:任务描述 本关任务:编写一个程序构建哈夫曼树和生成哈夫曼编码。 相关知识 为了完成本关任务,你需要掌握: 1.如何构建哈夫曼树, 2.如何生成哈夫曼编码。 测试说明 平台会对你编写的代码进行测试: 测试输入: 1192677541518462450242195190181174157138124123 (用户分别输入所列单词的频度) 预
    243 14
    【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
    |
    9月前
    |
    Java C++
    【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
    本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
    205 12
    |
    9月前
    |
    存储 算法 测试技术
    【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
    本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
    295 3
    |
    10月前
    |
    存储 缓存 安全
    Java 集合江湖:底层数据结构的大揭秘!
    小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
    162 5