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

    目录
    相关文章
    |
    28天前
    |
    存储 Java
    Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。
    【10月更文挑战第19天】本文详细介绍了Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。HashMap以其高效的插入、查找和删除操作著称,而TreeMap则擅长于保持元素的自然排序或自定义排序,两者各具优势,适用于不同的开发场景。
    42 1
    |
    30天前
    |
    存储 Java
    告别混乱!用Java Map优雅管理你的数据结构
    【10月更文挑战第17天】在软件开发中,随着项目复杂度增加,数据结构的组织和管理至关重要。Java中的Map接口提供了一种优雅的解决方案,帮助我们高效、清晰地管理数据。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,有效提升了代码质量和维护性。
    82 2
    |
    30天前
    |
    存储 Java 开发者
    Java Map实战:用HashMap和TreeMap轻松解决复杂数据结构问题!
    【10月更文挑战第17天】本文深入探讨了Java中HashMap和TreeMap两种Map类型的特性和应用场景。HashMap基于哈希表实现,支持高效的数据操作且允许键值为null;TreeMap基于红黑树实现,支持自然排序或自定义排序,确保元素有序。文章通过具体示例展示了两者的实战应用,帮助开发者根据实际需求选择合适的数据结构,提高开发效率。
    61 2
    |
    18天前
    |
    存储 搜索推荐 算法
    【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
    本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
    60 16
    |
    13天前
    |
    缓存 算法 Java
    本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
    在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
    35 6
    |
    19天前
    |
    存储 Java 索引
    Java中的数据结构:ArrayList和LinkedList的比较
    【10月更文挑战第28天】在Java编程世界中,数据结构是构建复杂程序的基石。本文将深入探讨两种常用的数据结构:ArrayList和LinkedList,通过直观的比喻和实例分析,揭示它们各自的优势与局限,帮助你在面对不同的编程挑战时做出明智的选择。
    |
    27天前
    |
    存储 算法 Java
    Java 中常用的数据结构
    【10月更文挑战第20天】这些数据结构在 Java 编程中都有着广泛的应用,掌握它们的特点和用法对于提高编程能力和解决实际问题非常重要。
    29 6
    |
    28天前
    |
    存储 Java 开发者
    Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效
    【10月更文挑战第19天】在软件开发中,随着项目复杂度的增加,数据结构的组织和管理变得至关重要。Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,帮助开发者告别混乱,提升代码质量。
    27 1
    |
    1月前
    |
    存储 算法 Java
    Java常用的数据结构
    【10月更文挑战第3天】 在 Java 中,常用的数据结构包括数组、链表、栈、队列、树、图、哈希表和集合。每种数据结构都有其特点和适用场景,如数组适用于快速访问,链表适合频繁插入和删除,栈用于实现后进先出,队列用于先进先出,树和图用于复杂关系的表示和查找,哈希表提供高效的查找性能,集合用于存储不重复的元素。合理选择和组合使用这些数据结构,可以显著提升程序的性能和效率。
    |
    1月前
    |
    Java C++
    【数据结构】探索红黑树的奥秘:自平衡原理图解及与二叉查找树的比较
    本文深入解析红黑树的自平衡原理,介绍其五大原则,并通过图解和代码示例展示其内部机制。同时,对比红黑树与二叉查找树的性能差异,帮助读者更好地理解这两种数据结构的特点和应用场景。
    31 0